feat: Support atlas_client module:
- Add client for atlas module - Add unit tests to test the workflow - Remove println statements from file_or_image_exists - Remove println statements from link processing loop
This commit is contained in:
@@ -148,7 +148,7 @@ pub fn (c Collection) file_exists(name string) bool {
|
||||
}
|
||||
|
||||
pub fn (c Collection) file_or_image_exists(name string) bool {
|
||||
f := c.files[name] or { return false }
|
||||
_ := c.files[name] or { return false }
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
@@ -118,7 +118,6 @@ fn (mut p Page) find_links(content string) ![]Link {
|
||||
link.is_file_link = false
|
||||
link.is_image_link = false
|
||||
}
|
||||
println(link)
|
||||
links << link
|
||||
|
||||
pos = close_paren + 1
|
||||
@@ -232,7 +231,6 @@ fn (mut p Page) process_links(mut export_dir pathlib.Path) !string {
|
||||
|
||||
// Process links in reverse order to maintain string positions
|
||||
for mut link in links.reverse() {
|
||||
println(link)
|
||||
if link.status != .found {
|
||||
continue
|
||||
}
|
||||
|
||||
93
lib/web/atlas_client/README.md
Normal file
93
lib/web/atlas_client/README.md
Normal file
@@ -0,0 +1,93 @@
|
||||
# AtlasClient
|
||||
|
||||
A simple API for accessing document collections exported by the `atlas` module.
|
||||
|
||||
## What It Does
|
||||
|
||||
AtlasClient provides methods to:
|
||||
|
||||
- List collections, pages, files, and images
|
||||
- Check if resources exist
|
||||
- Get file paths and content
|
||||
- Access metadata (links, errors)
|
||||
- Copy images from pages
|
||||
|
||||
## Quick Start
|
||||
|
||||
```v
|
||||
import incubaid.herolib.web.atlas_client
|
||||
|
||||
// Create client
|
||||
mut client := atlas_client.new(export_dir: '/tmp/atlas_export')!
|
||||
|
||||
// List collections
|
||||
collections := client.list_collections()!
|
||||
|
||||
// Get page content
|
||||
content := client.get_page_content('my_collection', 'page_name')!
|
||||
|
||||
// Check for errors
|
||||
if client.has_errors('my_collection')! {
|
||||
errors := client.get_collection_errors('my_collection')!
|
||||
}
|
||||
```
|
||||
|
||||
## Export Structure
|
||||
|
||||
Atlas exports to this structure:
|
||||
|
||||
```txt
|
||||
export_dir/
|
||||
├── content/
|
||||
│ └── collection_name/
|
||||
│ ├── page.md
|
||||
│ ├── image.png
|
||||
│ └── file.pdf
|
||||
└── meta/
|
||||
└── collection_name.json
|
||||
```
|
||||
|
||||
## Key Methods
|
||||
|
||||
**Collections:**
|
||||
|
||||
- `list_collections()` - List all collections
|
||||
|
||||
**Pages:**
|
||||
|
||||
- `list_pages(collection)` - List pages in collection
|
||||
- `page_exists(collection, page)` - Check if page exists
|
||||
- `get_page_content(collection, page)` - Get page markdown content
|
||||
- `get_page_path(collection, page)` - Get page file path
|
||||
|
||||
**Files & Images:**
|
||||
|
||||
- `list_files(collection)` - List non-page, non-image files
|
||||
- `list_images(collection)` - List image files
|
||||
- `get_file_path(collection, file)` - Get file path
|
||||
- `get_image_path(collection, image)` - Get image path
|
||||
- `copy_images(collection, page, dest)` - Copy page images to dest/img/
|
||||
|
||||
**Metadata:**
|
||||
|
||||
- `get_collection_metadata(collection)` - Get full metadata
|
||||
- `get_page_links(collection, page)` - Get links from page
|
||||
- `get_collection_errors(collection)` - Get collection errors
|
||||
- `has_errors(collection)` - Check if collection has errors
|
||||
|
||||
## Naming Convention
|
||||
|
||||
Names are normalized using `name_fix_no_underscore_no_ext()`:
|
||||
|
||||
- `My_Page-Name.md` → `mypagename`
|
||||
- Removes: underscores, dashes, special chars, extensions
|
||||
- Converts to lowercase
|
||||
|
||||
## Example
|
||||
|
||||
See `examples/data/atlas_client/basic_usage.vsh` for a complete working example.
|
||||
|
||||
## See Also
|
||||
|
||||
- `lib/data/atlas/` - Atlas module for exporting collections
|
||||
- `lib/web/doctreeclient/` - Alternative client for doctree collections
|
||||
422
lib/web/atlas_client/client.v
Normal file
422
lib/web/atlas_client/client.v
Normal file
@@ -0,0 +1,422 @@
|
||||
module atlas_client
|
||||
|
||||
import incubaid.herolib.core.pathlib
|
||||
import incubaid.herolib.core.texttools
|
||||
import os
|
||||
import json
|
||||
|
||||
// List of recognized image file extensions
|
||||
const image_extensions = ['.png', '.jpg', '.jpeg', '.gif', '.svg', '.webp', '.bmp', '.tiff', '.ico']
|
||||
|
||||
// CollectionMetadata represents the metadata stored in meta/{collection}.json
|
||||
pub struct CollectionMetadata {
|
||||
pub mut:
|
||||
name string
|
||||
path string
|
||||
pages map[string]PageMetadata
|
||||
files map[string]FileMetadata
|
||||
errors []ErrorMetadata
|
||||
}
|
||||
|
||||
pub struct PageMetadata {
|
||||
pub mut:
|
||||
name string
|
||||
path string
|
||||
collection_name string
|
||||
links []LinkMetadata
|
||||
}
|
||||
|
||||
pub struct FileMetadata {
|
||||
pub mut:
|
||||
name string
|
||||
path string
|
||||
}
|
||||
|
||||
pub struct LinkMetadata {
|
||||
pub mut:
|
||||
src string
|
||||
text string
|
||||
target string
|
||||
line int
|
||||
target_collection_name string
|
||||
target_item_name string
|
||||
status string
|
||||
is_file_link bool
|
||||
is_image_link bool
|
||||
}
|
||||
|
||||
pub struct ErrorMetadata {
|
||||
pub mut:
|
||||
category string
|
||||
page_key string
|
||||
message string
|
||||
line int
|
||||
}
|
||||
|
||||
// get_page_path returns the path for a page in a collection
|
||||
// Pages are stored in {export_dir}/content/{collection}/{page}.md
|
||||
pub fn (mut c AtlasClient) get_page_path(collection_name string, page_name string) !string {
|
||||
// Apply name normalization (atlas uses name_fix_no_underscore_no_ext)
|
||||
fixed_collection_name := texttools.name_fix_no_underscore_no_ext(collection_name)
|
||||
fixed_page_name := texttools.name_fix_no_underscore_no_ext(page_name)
|
||||
|
||||
// Check if export directory exists
|
||||
if !os.exists(c.export_dir) {
|
||||
return c.error_export_dir_not_found(export_dir: c.export_dir)
|
||||
}
|
||||
|
||||
// Construct the page path
|
||||
page_path := os.join_path(c.export_dir, 'content', fixed_collection_name, '${fixed_page_name}.md')
|
||||
|
||||
// Check if the page file exists
|
||||
if !os.exists(page_path) {
|
||||
return c.error_page_not_found(
|
||||
collection_name: collection_name
|
||||
page_name: page_name
|
||||
)
|
||||
}
|
||||
|
||||
return page_path
|
||||
}
|
||||
|
||||
// get_file_path returns the path for a file in a collection
|
||||
// Files are stored in {export_dir}/content/{collection}/{filename}
|
||||
pub fn (mut c AtlasClient) get_file_path(collection_name string, file_name string) !string {
|
||||
// Apply name normalization
|
||||
fixed_collection_name := texttools.name_fix_no_underscore_no_ext(collection_name)
|
||||
// Files keep their original names with extensions
|
||||
fixed_file_name := texttools.name_fix_keepext(file_name)
|
||||
|
||||
// Check if export directory exists
|
||||
if !os.exists(c.export_dir) {
|
||||
return c.error_export_dir_not_found(export_dir: c.export_dir)
|
||||
}
|
||||
|
||||
// Construct the file path
|
||||
file_path := os.join_path(c.export_dir, 'content', fixed_collection_name, fixed_file_name)
|
||||
|
||||
// Check if the file exists
|
||||
if !os.exists(file_path) {
|
||||
return c.error_file_not_found(
|
||||
collection_name: collection_name
|
||||
file_name: file_name
|
||||
)
|
||||
}
|
||||
|
||||
return file_path
|
||||
}
|
||||
|
||||
// get_image_path returns the path for an image in a collection
|
||||
// Images are stored in {export_dir}/content/{collection}/{imagename}
|
||||
pub fn (mut c AtlasClient) get_image_path(collection_name string, image_name string) !string {
|
||||
// Apply name normalization
|
||||
fixed_collection_name := texttools.name_fix_no_underscore_no_ext(collection_name)
|
||||
// Images keep their original names with extensions
|
||||
fixed_image_name := texttools.name_fix_keepext(image_name)
|
||||
|
||||
// Check if export directory exists
|
||||
if !os.exists(c.export_dir) {
|
||||
return c.error_export_dir_not_found(export_dir: c.export_dir)
|
||||
}
|
||||
|
||||
// Construct the image path
|
||||
image_path := os.join_path(c.export_dir, 'content', fixed_collection_name, fixed_image_name)
|
||||
|
||||
// Check if the image exists
|
||||
if !os.exists(image_path) {
|
||||
return c.error_image_not_found(
|
||||
collection_name: collection_name
|
||||
image_name: image_name
|
||||
)
|
||||
}
|
||||
|
||||
return image_path
|
||||
}
|
||||
|
||||
// page_exists checks if a page exists in a collection
|
||||
pub fn (mut c AtlasClient) page_exists(collection_name string, page_name string) bool {
|
||||
// Try to get the page path - if it succeeds, the page exists
|
||||
_ := c.get_page_path(collection_name, page_name) or { return false }
|
||||
return true
|
||||
}
|
||||
|
||||
// file_exists checks if a file exists in a collection
|
||||
pub fn (mut c AtlasClient) file_exists(collection_name string, file_name string) bool {
|
||||
// Try to get the file path - if it succeeds, the file exists
|
||||
_ := c.get_file_path(collection_name, file_name) or { return false }
|
||||
return true
|
||||
}
|
||||
|
||||
// image_exists checks if an image exists in a collection
|
||||
pub fn (mut c AtlasClient) image_exists(collection_name string, image_name string) bool {
|
||||
// Try to get the image path - if it succeeds, the image exists
|
||||
_ := c.get_image_path(collection_name, image_name) or { return false }
|
||||
return true
|
||||
}
|
||||
|
||||
// get_page_content returns the content of a page in a collection
|
||||
pub fn (mut c AtlasClient) get_page_content(collection_name string, page_name string) !string {
|
||||
// Get the path for the page
|
||||
page_path := c.get_page_path(collection_name, page_name)!
|
||||
|
||||
// Use pathlib to read the file content
|
||||
mut path := pathlib.get_file(path: page_path)!
|
||||
|
||||
// Check if the file exists
|
||||
if !path.exists() {
|
||||
return c.error_page_file_not_exists(page_path: page_path)
|
||||
}
|
||||
|
||||
// Read and return the file content
|
||||
return path.read()!
|
||||
}
|
||||
|
||||
// list_collections returns a list of all collection names
|
||||
// Collections are directories in {export_dir}/content/
|
||||
pub fn (mut c AtlasClient) list_collections() ![]string {
|
||||
content_dir := os.join_path(c.export_dir, 'content')
|
||||
|
||||
// Check if content directory exists
|
||||
if !os.exists(content_dir) {
|
||||
return c.error_invalid_export_structure(content_dir: content_dir)
|
||||
}
|
||||
|
||||
// Get all subdirectories in content/
|
||||
mut collections := []string{}
|
||||
entries := os.ls(content_dir)!
|
||||
|
||||
for entry in entries {
|
||||
entry_path := os.join_path(content_dir, entry)
|
||||
if os.is_dir(entry_path) {
|
||||
collections << entry
|
||||
}
|
||||
}
|
||||
|
||||
return collections
|
||||
}
|
||||
|
||||
// list_pages returns a list of all page names in a collection
|
||||
// Uses metadata to get the authoritative list of pages that belong to this collection
|
||||
pub fn (mut c AtlasClient) list_pages(collection_name string) ![]string {
|
||||
// Get metadata which contains the authoritative list of pages
|
||||
metadata := c.get_collection_metadata(collection_name)!
|
||||
|
||||
// Extract page names from metadata
|
||||
mut page_names := []string{}
|
||||
for page_name, _ in metadata.pages {
|
||||
page_names << page_name
|
||||
}
|
||||
|
||||
return page_names
|
||||
}
|
||||
|
||||
// list_files returns a list of all file names in a collection (excluding pages and images)
|
||||
pub fn (mut c AtlasClient) list_files(collection_name string) ![]string {
|
||||
// Apply name normalization
|
||||
fixed_collection_name := texttools.name_fix_no_underscore_no_ext(collection_name)
|
||||
|
||||
collection_dir := os.join_path(c.export_dir, 'content', fixed_collection_name)
|
||||
|
||||
// Check if collection directory exists
|
||||
if !os.exists(collection_dir) {
|
||||
return c.error_collection_not_found(collection_name: collection_name)
|
||||
}
|
||||
|
||||
// Get all files that are not .md and not images
|
||||
mut file_names := []string{}
|
||||
entries := os.ls(collection_dir)!
|
||||
|
||||
for entry in entries {
|
||||
entry_path := os.join_path(collection_dir, entry)
|
||||
|
||||
// Skip directories
|
||||
if os.is_dir(entry_path) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Skip .md files (pages)
|
||||
if entry.ends_with('.md') {
|
||||
continue
|
||||
}
|
||||
|
||||
// Check if it's an image
|
||||
mut is_image := false
|
||||
for ext in image_extensions {
|
||||
if entry.ends_with(ext) {
|
||||
is_image = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Add to file_names if it's not an image
|
||||
if !is_image {
|
||||
file_names << entry
|
||||
}
|
||||
}
|
||||
|
||||
return file_names
|
||||
}
|
||||
|
||||
// list_images returns a list of all image names in a collection
|
||||
pub fn (mut c AtlasClient) list_images(collection_name string) ![]string {
|
||||
// Apply name normalization
|
||||
fixed_collection_name := texttools.name_fix_no_underscore_no_ext(collection_name)
|
||||
|
||||
collection_dir := os.join_path(c.export_dir, 'content', fixed_collection_name)
|
||||
|
||||
// Check if collection directory exists
|
||||
if !os.exists(collection_dir) {
|
||||
return c.error_collection_not_found(collection_name: collection_name)
|
||||
}
|
||||
|
||||
// Get all image files
|
||||
mut image_names := []string{}
|
||||
entries := os.ls(collection_dir)!
|
||||
|
||||
for entry in entries {
|
||||
entry_path := os.join_path(collection_dir, entry)
|
||||
|
||||
// Skip directories
|
||||
if os.is_dir(entry_path) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Check if it's an image
|
||||
for ext in image_extensions {
|
||||
if entry.ends_with(ext) {
|
||||
image_names << entry
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return image_names
|
||||
}
|
||||
|
||||
// list_pages_map returns a map of collection names to a list of page names within that collection.
|
||||
// The structure is map[collectionname][]pagename.
|
||||
pub fn (mut c AtlasClient) list_pages_map() !map[string][]string {
|
||||
mut result := map[string][]string{}
|
||||
collections := c.list_collections()!
|
||||
|
||||
for col_name in collections {
|
||||
mut page_names := c.list_pages(col_name)!
|
||||
page_names.sort()
|
||||
result[col_name] = page_names
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// list_markdown returns the collections and their pages in markdown format.
|
||||
pub fn (mut c AtlasClient) list_markdown() !string {
|
||||
mut markdown_output := ''
|
||||
pages_map := c.list_pages_map()!
|
||||
|
||||
if pages_map.len == 0 {
|
||||
return 'No collections or pages found in this atlas export.'
|
||||
}
|
||||
|
||||
mut sorted_collections := pages_map.keys()
|
||||
sorted_collections.sort()
|
||||
|
||||
for col_name in sorted_collections {
|
||||
page_names := pages_map[col_name]
|
||||
markdown_output += '## ${col_name}\n'
|
||||
if page_names.len == 0 {
|
||||
markdown_output += ' * No pages in this collection.\n'
|
||||
} else {
|
||||
for page_name in page_names {
|
||||
markdown_output += ' * ${page_name}\n'
|
||||
}
|
||||
}
|
||||
markdown_output += '\n' // Add a newline for spacing between collections
|
||||
}
|
||||
return markdown_output
|
||||
}
|
||||
|
||||
// get_collection_metadata reads and parses the metadata JSON file for a collection
|
||||
// Metadata is stored in {export_dir}/meta/{collection}.json
|
||||
pub fn (mut c AtlasClient) get_collection_metadata(collection_name string) !CollectionMetadata {
|
||||
// Apply name normalization
|
||||
fixed_collection_name := texttools.name_fix_no_underscore_no_ext(collection_name)
|
||||
|
||||
meta_path := os.join_path(c.export_dir, 'meta', '${fixed_collection_name}.json')
|
||||
|
||||
// Check if metadata file exists
|
||||
if !os.exists(meta_path) {
|
||||
return c.error_collection_not_found_at(
|
||||
collection_name: collection_name
|
||||
path: meta_path
|
||||
)
|
||||
}
|
||||
|
||||
// Read and parse the JSON file
|
||||
content := os.read_file(meta_path)!
|
||||
metadata := json.decode(CollectionMetadata, content)!
|
||||
|
||||
return metadata
|
||||
}
|
||||
|
||||
// get_page_links returns the links found in a page by reading the metadata
|
||||
pub fn (mut c AtlasClient) get_page_links(collection_name string, page_name string) ![]LinkMetadata {
|
||||
// Get collection metadata
|
||||
metadata := c.get_collection_metadata(collection_name)!
|
||||
|
||||
// Apply name normalization to page name
|
||||
fixed_page_name := texttools.name_fix_no_underscore_no_ext(page_name)
|
||||
|
||||
// Find the page in metadata
|
||||
if fixed_page_name in metadata.pages {
|
||||
return metadata.pages[fixed_page_name].links
|
||||
}
|
||||
|
||||
return c.error_page_not_found_in_metadata(
|
||||
collection_name: collection_name
|
||||
page_name: page_name
|
||||
)
|
||||
}
|
||||
|
||||
// get_collection_errors returns the errors for a collection from metadata
|
||||
pub fn (mut c AtlasClient) get_collection_errors(collection_name string) ![]ErrorMetadata {
|
||||
metadata := c.get_collection_metadata(collection_name)!
|
||||
return metadata.errors
|
||||
}
|
||||
|
||||
// has_errors checks if a collection has any errors
|
||||
pub fn (mut c AtlasClient) has_errors(collection_name string) bool {
|
||||
errors := c.get_collection_errors(collection_name) or { return false }
|
||||
return errors.len > 0
|
||||
}
|
||||
|
||||
// copy_images copies all images linked in a page to a destination directory
|
||||
// This is compatible with the doctreeclient API
|
||||
pub fn (mut c AtlasClient) copy_images(collection_name string, page_name string, destination_path string) ! {
|
||||
// Get page content
|
||||
page_content := c.get_page_content(collection_name, page_name)!
|
||||
|
||||
// Extract image links from content
|
||||
image_names := extract_image_links(page_content, true)!
|
||||
|
||||
// Ensure the destination directory exists
|
||||
os.mkdir_all(destination_path)!
|
||||
|
||||
// Create an 'img' subdirectory within the destination
|
||||
images_dest_path := os.join_path(destination_path, 'img')
|
||||
os.mkdir_all(images_dest_path)!
|
||||
|
||||
// Copy each linked image
|
||||
for image_name in image_names {
|
||||
// Get the image path
|
||||
image_path := c.get_image_path(collection_name, image_name) or {
|
||||
// If an image is not found, return an error
|
||||
return c.error_image_not_found_linked(
|
||||
collection_name: collection_name
|
||||
image_name: image_name
|
||||
)
|
||||
}
|
||||
|
||||
image_file_name := os.base(image_path)
|
||||
dest_image_path := os.join_path(images_dest_path, image_file_name)
|
||||
os.cp(image_path, dest_image_path)!
|
||||
}
|
||||
}
|
||||
670
lib/web/atlas_client/client_test.v
Normal file
670
lib/web/atlas_client/client_test.v
Normal file
@@ -0,0 +1,670 @@
|
||||
module atlas_client
|
||||
|
||||
import os
|
||||
import incubaid.herolib.core.texttools { name_fix_no_underscore_no_ext }
|
||||
|
||||
// Helper function to create a test export directory structure
|
||||
fn setup_test_export() string {
|
||||
test_dir := os.join_path(os.temp_dir(), 'atlas_client_test_${os.getpid()}')
|
||||
|
||||
// Clean up if exists
|
||||
if os.exists(test_dir) {
|
||||
os.rmdir_all(test_dir) or {}
|
||||
}
|
||||
|
||||
// Create directory structure
|
||||
os.mkdir_all(os.join_path(test_dir, 'content', 'testcollection')) or { panic(err) }
|
||||
os.mkdir_all(os.join_path(test_dir, 'content', 'anothercollection')) or { panic(err) }
|
||||
os.mkdir_all(os.join_path(test_dir, 'meta')) or { panic(err) }
|
||||
|
||||
// Create test pages
|
||||
os.write_file(os.join_path(test_dir, 'content', 'testcollection', 'page1.md'), '# Page 1\n\nContent here.') or {
|
||||
panic(err)
|
||||
}
|
||||
os.write_file(os.join_path(test_dir, 'content', 'testcollection', 'page2.md'), '# Page 2\n\n') or {
|
||||
panic(err)
|
||||
}
|
||||
os.write_file(os.join_path(test_dir, 'content', 'anothercollection', 'intro.md'),
|
||||
'# Intro\n\nWelcome!') or { panic(err) }
|
||||
|
||||
// Create test images
|
||||
os.write_file(os.join_path(test_dir, 'content', 'testcollection', 'logo.png'), 'fake png data') or {
|
||||
panic(err)
|
||||
}
|
||||
os.write_file(os.join_path(test_dir, 'content', 'testcollection', 'banner.jpg'), 'fake jpg data') or {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Create test files
|
||||
os.write_file(os.join_path(test_dir, 'content', 'testcollection', 'data.csv'), 'col1,col2\nval1,val2') or {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Create metadata files
|
||||
metadata1 := '{
|
||||
"name": "testcollection",
|
||||
"path": "",
|
||||
"pages": {
|
||||
"page1": {
|
||||
"name": "page1",
|
||||
"path": "",
|
||||
"collection_name": "testcollection",
|
||||
"links": []
|
||||
},
|
||||
"page2": {
|
||||
"name": "page2",
|
||||
"path": "",
|
||||
"collection_name": "testcollection",
|
||||
"links": [
|
||||
{
|
||||
"src": "logo.png",
|
||||
"text": "logo",
|
||||
"target": "logo.png",
|
||||
"line": 3,
|
||||
"target_collection_name": "testcollection",
|
||||
"target_item_name": "logo",
|
||||
"status": "ok",
|
||||
"is_file_link": false,
|
||||
"is_image_link": true
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"files": {},
|
||||
"errors": []
|
||||
}'
|
||||
os.write_file(os.join_path(test_dir, 'meta', 'testcollection.json'), metadata1) or {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
metadata2 := '{
|
||||
"name": "anothercollection",
|
||||
"path": "",
|
||||
"pages": {
|
||||
"intro": {
|
||||
"name": "intro",
|
||||
"path": "",
|
||||
"collection_name": "anothercollection",
|
||||
"links": []
|
||||
}
|
||||
},
|
||||
"files": {},
|
||||
"errors": [
|
||||
{
|
||||
"category": "test",
|
||||
"page_key": "intro",
|
||||
"message": "Test error",
|
||||
"line": 10
|
||||
}
|
||||
]
|
||||
}'
|
||||
os.write_file(os.join_path(test_dir, 'meta', 'anothercollection.json'), metadata2) or {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return test_dir
|
||||
}
|
||||
|
||||
// Helper function to cleanup test directory
|
||||
fn cleanup_test_export(test_dir string) {
|
||||
os.rmdir_all(test_dir) or {}
|
||||
}
|
||||
|
||||
// Test creating a new client
|
||||
fn test_new_client() {
|
||||
test_dir := setup_test_export()
|
||||
defer { cleanup_test_export(test_dir) }
|
||||
|
||||
mut client := new(export_dir: test_dir) or { panic(err) }
|
||||
assert client.export_dir == test_dir
|
||||
}
|
||||
|
||||
// Test creating client with non-existent directory
|
||||
fn test_new_client_nonexistent_dir() {
|
||||
mut client := new(export_dir: '/nonexistent/path/to/export') or { panic(err) }
|
||||
// Client creation should succeed, but operations will fail
|
||||
assert client.export_dir == '/nonexistent/path/to/export'
|
||||
}
|
||||
|
||||
// Test get_page_path - success
|
||||
fn test_get_page_path_success() {
|
||||
test_dir := setup_test_export()
|
||||
defer { cleanup_test_export(test_dir) }
|
||||
|
||||
mut client := new(export_dir: test_dir) or { panic(err) }
|
||||
path := client.get_page_path('testcollection', 'page1') or { panic(err) }
|
||||
|
||||
assert path.contains('testcollection')
|
||||
assert path.ends_with('page1.md')
|
||||
assert os.exists(path)
|
||||
}
|
||||
|
||||
// Test get_page_path - with naming normalization
|
||||
fn test_get_page_path_normalization() {
|
||||
test_dir := setup_test_export()
|
||||
defer { cleanup_test_export(test_dir) }
|
||||
|
||||
// Create a page with normalized name
|
||||
normalized_name := name_fix_no_underscore_no_ext('Test_Page-Name')
|
||||
os.write_file(os.join_path(test_dir, 'content', 'testcollection', '${normalized_name}.md'),
|
||||
'# Test') or { panic(err) }
|
||||
|
||||
mut client := new(export_dir: test_dir) or { panic(err) }
|
||||
|
||||
// Should find the page regardless of input format
|
||||
path := client.get_page_path('testcollection', 'Test_Page-Name') or { panic(err) }
|
||||
assert os.exists(path)
|
||||
}
|
||||
|
||||
// Test get_page_path - page not found
|
||||
fn test_get_page_path_not_found() {
|
||||
test_dir := setup_test_export()
|
||||
defer { cleanup_test_export(test_dir) }
|
||||
|
||||
mut client := new(export_dir: test_dir) or { panic(err) }
|
||||
client.get_page_path('testcollection', 'nonexistent') or {
|
||||
assert err.msg().contains('page_not_found')
|
||||
assert err.msg().contains('nonexistent')
|
||||
return
|
||||
}
|
||||
assert false, 'Should have returned an error'
|
||||
}
|
||||
|
||||
// Test get_page_path - export dir not found
|
||||
fn test_get_page_path_no_export_dir() {
|
||||
mut client := new(export_dir: '/nonexistent/path') or { panic(err) }
|
||||
client.get_page_path('testcollection', 'page1') or {
|
||||
assert err.msg().contains('export_dir_not_found')
|
||||
return
|
||||
}
|
||||
assert false, 'Should have returned an error'
|
||||
}
|
||||
|
||||
// Test get_file_path - success
|
||||
fn test_get_file_path_success() {
|
||||
test_dir := setup_test_export()
|
||||
defer { cleanup_test_export(test_dir) }
|
||||
|
||||
mut client := new(export_dir: test_dir) or { panic(err) }
|
||||
path := client.get_file_path('testcollection', 'data.csv') or { panic(err) }
|
||||
|
||||
assert path.contains('testcollection')
|
||||
assert path.ends_with('data.csv')
|
||||
assert os.exists(path)
|
||||
}
|
||||
|
||||
// Test get_file_path - file not found
|
||||
fn test_get_file_path_not_found() {
|
||||
test_dir := setup_test_export()
|
||||
defer { cleanup_test_export(test_dir) }
|
||||
|
||||
mut client := new(export_dir: test_dir) or { panic(err) }
|
||||
client.get_file_path('testcollection', 'missing.pdf') or {
|
||||
assert err.msg().contains('file_not_found')
|
||||
assert err.msg().contains('missing.pdf')
|
||||
return
|
||||
}
|
||||
assert false, 'Should have returned an error'
|
||||
}
|
||||
|
||||
// Test get_image_path - success
|
||||
fn test_get_image_path_success() {
|
||||
test_dir := setup_test_export()
|
||||
defer { cleanup_test_export(test_dir) }
|
||||
|
||||
mut client := new(export_dir: test_dir) or { panic(err) }
|
||||
path := client.get_image_path('testcollection', 'logo.png') or { panic(err) }
|
||||
|
||||
assert path.contains('testcollection')
|
||||
assert path.ends_with('logo.png')
|
||||
assert os.exists(path)
|
||||
}
|
||||
|
||||
// Test get_image_path - image not found
|
||||
fn test_get_image_path_not_found() {
|
||||
test_dir := setup_test_export()
|
||||
defer { cleanup_test_export(test_dir) }
|
||||
|
||||
mut client := new(export_dir: test_dir) or { panic(err) }
|
||||
client.get_image_path('testcollection', 'missing.jpg') or {
|
||||
assert err.msg().contains('image_not_found')
|
||||
assert err.msg().contains('missing.jpg')
|
||||
return
|
||||
}
|
||||
assert false, 'Should have returned an error'
|
||||
}
|
||||
|
||||
// Test page_exists - true
|
||||
fn test_page_exists_true() {
|
||||
test_dir := setup_test_export()
|
||||
defer { cleanup_test_export(test_dir) }
|
||||
|
||||
mut client := new(export_dir: test_dir) or { panic(err) }
|
||||
exists := client.page_exists('testcollection', 'page1')
|
||||
assert exists == true
|
||||
}
|
||||
|
||||
// Test page_exists - false
|
||||
fn test_page_exists_false() {
|
||||
test_dir := setup_test_export()
|
||||
defer { cleanup_test_export(test_dir) }
|
||||
|
||||
mut client := new(export_dir: test_dir) or { panic(err) }
|
||||
exists := client.page_exists('testcollection', 'nonexistent')
|
||||
assert exists == false
|
||||
}
|
||||
|
||||
// Test file_exists - true
|
||||
fn test_file_exists_true() {
|
||||
test_dir := setup_test_export()
|
||||
defer { cleanup_test_export(test_dir) }
|
||||
|
||||
mut client := new(export_dir: test_dir) or { panic(err) }
|
||||
exists := client.file_exists('testcollection', 'data.csv')
|
||||
assert exists == true
|
||||
}
|
||||
|
||||
// Test file_exists - false
|
||||
fn test_file_exists_false() {
|
||||
test_dir := setup_test_export()
|
||||
defer { cleanup_test_export(test_dir) }
|
||||
|
||||
mut client := new(export_dir: test_dir) or { panic(err) }
|
||||
exists := client.file_exists('testcollection', 'missing.pdf')
|
||||
assert exists == false
|
||||
}
|
||||
|
||||
// Test image_exists - true
|
||||
fn test_image_exists_true() {
|
||||
test_dir := setup_test_export()
|
||||
defer { cleanup_test_export(test_dir) }
|
||||
|
||||
mut client := new(export_dir: test_dir) or { panic(err) }
|
||||
exists := client.image_exists('testcollection', 'logo.png')
|
||||
assert exists == true
|
||||
}
|
||||
|
||||
// Test image_exists - false
|
||||
fn test_image_exists_false() {
|
||||
test_dir := setup_test_export()
|
||||
defer { cleanup_test_export(test_dir) }
|
||||
|
||||
mut client := new(export_dir: test_dir) or { panic(err) }
|
||||
exists := client.image_exists('testcollection', 'missing.svg')
|
||||
assert exists == false
|
||||
}
|
||||
|
||||
// Test get_page_content - success
|
||||
fn test_get_page_content_success() {
|
||||
test_dir := setup_test_export()
|
||||
defer { cleanup_test_export(test_dir) }
|
||||
|
||||
mut client := new(export_dir: test_dir) or { panic(err) }
|
||||
content := client.get_page_content('testcollection', 'page1') or { panic(err) }
|
||||
|
||||
assert content.contains('# Page 1')
|
||||
assert content.contains('Content here.')
|
||||
}
|
||||
|
||||
// Test get_page_content - page not found
|
||||
fn test_get_page_content_not_found() {
|
||||
test_dir := setup_test_export()
|
||||
defer { cleanup_test_export(test_dir) }
|
||||
|
||||
mut client := new(export_dir: test_dir) or { panic(err) }
|
||||
client.get_page_content('testcollection', 'nonexistent') or {
|
||||
assert err.msg().contains('page_not_found')
|
||||
return
|
||||
}
|
||||
assert false, 'Should have returned an error'
|
||||
}
|
||||
|
||||
// Test list_collections
|
||||
fn test_list_collections() {
|
||||
test_dir := setup_test_export()
|
||||
defer { cleanup_test_export(test_dir) }
|
||||
|
||||
mut client := new(export_dir: test_dir) or { panic(err) }
|
||||
collections := client.list_collections() or { panic(err) }
|
||||
|
||||
assert collections.len == 2
|
||||
assert 'testcollection' in collections
|
||||
assert 'anothercollection' in collections
|
||||
}
|
||||
|
||||
// Test list_collections - no content dir
|
||||
fn test_list_collections_no_content_dir() {
|
||||
test_dir := os.join_path(os.temp_dir(), 'empty_export_${os.getpid()}')
|
||||
os.mkdir_all(test_dir) or { panic(err) }
|
||||
defer { cleanup_test_export(test_dir) }
|
||||
|
||||
mut client := new(export_dir: test_dir) or { panic(err) }
|
||||
client.list_collections() or {
|
||||
assert err.msg().contains('invalid_export_structure')
|
||||
return
|
||||
}
|
||||
assert false, 'Should have returned an error'
|
||||
}
|
||||
|
||||
// Test list_pages - success
|
||||
fn test_list_pages_success() {
|
||||
test_dir := setup_test_export()
|
||||
defer { cleanup_test_export(test_dir) }
|
||||
|
||||
mut client := new(export_dir: test_dir) or { panic(err) }
|
||||
pages := client.list_pages('testcollection') or { panic(err) }
|
||||
|
||||
assert pages.len == 2
|
||||
assert 'page1' in pages
|
||||
assert 'page2' in pages
|
||||
}
|
||||
|
||||
// Test list_pages - collection not found
|
||||
fn test_list_pages_collection_not_found() {
|
||||
test_dir := setup_test_export()
|
||||
defer { cleanup_test_export(test_dir) }
|
||||
|
||||
mut client := new(export_dir: test_dir) or { panic(err) }
|
||||
client.list_pages('nonexistent') or {
|
||||
assert err.msg().contains('collection_not_found')
|
||||
return
|
||||
}
|
||||
assert false, 'Should have returned an error'
|
||||
}
|
||||
|
||||
// Test list_files - success
|
||||
fn test_list_files_success() {
|
||||
test_dir := setup_test_export()
|
||||
defer { cleanup_test_export(test_dir) }
|
||||
|
||||
mut client := new(export_dir: test_dir) or { panic(err) }
|
||||
files := client.list_files('testcollection') or { panic(err) }
|
||||
|
||||
assert files.len == 1
|
||||
assert 'data.csv' in files
|
||||
}
|
||||
|
||||
// Test list_files - no files
|
||||
fn test_list_files_empty() {
|
||||
test_dir := setup_test_export()
|
||||
defer { cleanup_test_export(test_dir) }
|
||||
|
||||
mut client := new(export_dir: test_dir) or { panic(err) }
|
||||
files := client.list_files('anothercollection') or { panic(err) }
|
||||
|
||||
assert files.len == 0
|
||||
}
|
||||
|
||||
// Test list_images - success
|
||||
fn test_list_images_success() {
|
||||
test_dir := setup_test_export()
|
||||
defer { cleanup_test_export(test_dir) }
|
||||
|
||||
mut client := new(export_dir: test_dir) or { panic(err) }
|
||||
images := client.list_images('testcollection') or { panic(err) }
|
||||
|
||||
assert images.len == 2
|
||||
assert 'logo.png' in images
|
||||
assert 'banner.jpg' in images
|
||||
}
|
||||
|
||||
// Test list_images - no images
|
||||
fn test_list_images_empty() {
|
||||
test_dir := setup_test_export()
|
||||
defer { cleanup_test_export(test_dir) }
|
||||
|
||||
mut client := new(export_dir: test_dir) or { panic(err) }
|
||||
images := client.list_images('anothercollection') or { panic(err) }
|
||||
|
||||
assert images.len == 0
|
||||
}
|
||||
|
||||
// Test list_pages_map
|
||||
fn test_list_pages_map() {
|
||||
test_dir := setup_test_export()
|
||||
defer { cleanup_test_export(test_dir) }
|
||||
|
||||
mut client := new(export_dir: test_dir) or { panic(err) }
|
||||
pages_map := client.list_pages_map() or { panic(err) }
|
||||
|
||||
assert pages_map.len == 2
|
||||
assert 'testcollection' in pages_map
|
||||
assert 'anothercollection' in pages_map
|
||||
assert pages_map['testcollection'].len == 2
|
||||
assert pages_map['anothercollection'].len == 1
|
||||
}
|
||||
|
||||
// Test list_markdown
|
||||
fn test_list_markdown() {
|
||||
test_dir := setup_test_export()
|
||||
defer { cleanup_test_export(test_dir) }
|
||||
|
||||
mut client := new(export_dir: test_dir) or { panic(err) }
|
||||
markdown := client.list_markdown() or { panic(err) }
|
||||
|
||||
assert markdown.contains('testcollection')
|
||||
assert markdown.contains('anothercollection')
|
||||
assert markdown.contains('page1')
|
||||
assert markdown.contains('page2')
|
||||
assert markdown.contains('intro')
|
||||
assert markdown.contains('##')
|
||||
assert markdown.contains('*')
|
||||
}
|
||||
|
||||
// Test get_collection_metadata - success
|
||||
fn test_get_collection_metadata_success() {
|
||||
test_dir := setup_test_export()
|
||||
defer { cleanup_test_export(test_dir) }
|
||||
|
||||
mut client := new(export_dir: test_dir) or { panic(err) }
|
||||
metadata := client.get_collection_metadata('testcollection') or { panic(err) }
|
||||
|
||||
assert metadata.name == 'testcollection'
|
||||
assert metadata.pages.len == 2
|
||||
assert metadata.errors.len == 0
|
||||
}
|
||||
|
||||
// Test get_collection_metadata - with errors
|
||||
fn test_get_collection_metadata_with_errors() {
|
||||
test_dir := setup_test_export()
|
||||
defer { cleanup_test_export(test_dir) }
|
||||
|
||||
mut client := new(export_dir: test_dir) or { panic(err) }
|
||||
metadata := client.get_collection_metadata('anothercollection') or { panic(err) }
|
||||
|
||||
assert metadata.name == 'anothercollection'
|
||||
assert metadata.pages.len == 1
|
||||
assert metadata.errors.len == 1
|
||||
assert metadata.errors[0].message == 'Test error'
|
||||
assert metadata.errors[0].line == 10
|
||||
}
|
||||
|
||||
// Test get_collection_metadata - not found
|
||||
fn test_get_collection_metadata_not_found() {
|
||||
test_dir := setup_test_export()
|
||||
defer { cleanup_test_export(test_dir) }
|
||||
|
||||
mut client := new(export_dir: test_dir) or { panic(err) }
|
||||
client.get_collection_metadata('nonexistent') or {
|
||||
assert err.msg().contains('collection_not_found')
|
||||
return
|
||||
}
|
||||
assert false, 'Should have returned an error'
|
||||
}
|
||||
|
||||
// Test get_page_links - success
|
||||
fn test_get_page_links_success() {
|
||||
test_dir := setup_test_export()
|
||||
defer { cleanup_test_export(test_dir) }
|
||||
|
||||
mut client := new(export_dir: test_dir) or { panic(err) }
|
||||
links := client.get_page_links('testcollection', 'page2') or { panic(err) }
|
||||
|
||||
assert links.len == 1
|
||||
assert links[0].target_item_name == 'logo'
|
||||
assert links[0].target_collection_name == 'testcollection'
|
||||
assert links[0].is_image_link == true
|
||||
}
|
||||
|
||||
// Test get_page_links - no links
|
||||
fn test_get_page_links_empty() {
|
||||
test_dir := setup_test_export()
|
||||
defer { cleanup_test_export(test_dir) }
|
||||
|
||||
mut client := new(export_dir: test_dir) or { panic(err) }
|
||||
links := client.get_page_links('testcollection', 'page1') or { panic(err) }
|
||||
|
||||
assert links.len == 0
|
||||
}
|
||||
|
||||
// Test get_page_links - page not found
|
||||
fn test_get_page_links_page_not_found() {
|
||||
test_dir := setup_test_export()
|
||||
defer { cleanup_test_export(test_dir) }
|
||||
|
||||
mut client := new(export_dir: test_dir) or { panic(err) }
|
||||
client.get_page_links('testcollection', 'nonexistent') or {
|
||||
assert err.msg().contains('page_not_found')
|
||||
return
|
||||
}
|
||||
assert false, 'Should have returned an error'
|
||||
}
|
||||
|
||||
// Test get_collection_errors - success
|
||||
fn test_get_collection_errors_success() {
|
||||
test_dir := setup_test_export()
|
||||
defer { cleanup_test_export(test_dir) }
|
||||
|
||||
mut client := new(export_dir: test_dir) or { panic(err) }
|
||||
errors := client.get_collection_errors('anothercollection') or { panic(err) }
|
||||
|
||||
assert errors.len == 1
|
||||
assert errors[0].message == 'Test error'
|
||||
}
|
||||
|
||||
// Test get_collection_errors - no errors
|
||||
fn test_get_collection_errors_empty() {
|
||||
test_dir := setup_test_export()
|
||||
defer { cleanup_test_export(test_dir) }
|
||||
|
||||
mut client := new(export_dir: test_dir) or { panic(err) }
|
||||
errors := client.get_collection_errors('testcollection') or { panic(err) }
|
||||
|
||||
assert errors.len == 0
|
||||
}
|
||||
|
||||
// Test has_errors - true
|
||||
fn test_has_errors_true() {
|
||||
test_dir := setup_test_export()
|
||||
defer { cleanup_test_export(test_dir) }
|
||||
|
||||
mut client := new(export_dir: test_dir) or { panic(err) }
|
||||
has_errors := client.has_errors('anothercollection')
|
||||
|
||||
assert has_errors == true
|
||||
}
|
||||
|
||||
// Test has_errors - false
|
||||
fn test_has_errors_false() {
|
||||
test_dir := setup_test_export()
|
||||
defer { cleanup_test_export(test_dir) }
|
||||
|
||||
mut client := new(export_dir: test_dir) or { panic(err) }
|
||||
has_errors := client.has_errors('testcollection')
|
||||
|
||||
assert has_errors == false
|
||||
}
|
||||
|
||||
// Test has_errors - collection not found
|
||||
fn test_has_errors_collection_not_found() {
|
||||
test_dir := setup_test_export()
|
||||
defer { cleanup_test_export(test_dir) }
|
||||
|
||||
mut client := new(export_dir: test_dir) or { panic(err) }
|
||||
has_errors := client.has_errors('nonexistent')
|
||||
|
||||
assert has_errors == false
|
||||
}
|
||||
|
||||
// Test copy_images - success
|
||||
fn test_copy_images_success() {
|
||||
test_dir := setup_test_export()
|
||||
defer { cleanup_test_export(test_dir) }
|
||||
|
||||
dest_dir := os.join_path(os.temp_dir(), 'copy_dest_${os.getpid()}')
|
||||
os.mkdir_all(dest_dir) or { panic(err) }
|
||||
defer { cleanup_test_export(dest_dir) }
|
||||
|
||||
mut client := new(export_dir: test_dir) or { panic(err) }
|
||||
client.copy_images('testcollection', 'page2', dest_dir) or { panic(err) }
|
||||
|
||||
// Check that logo.png was copied to img subdirectory
|
||||
assert os.exists(os.join_path(dest_dir, 'img', 'logo.png'))
|
||||
}
|
||||
|
||||
// Test copy_images - no images
|
||||
fn test_copy_images_no_images() {
|
||||
test_dir := setup_test_export()
|
||||
defer { cleanup_test_export(test_dir) }
|
||||
|
||||
dest_dir := os.join_path(os.temp_dir(), 'copy_dest_empty_${os.getpid()}')
|
||||
os.mkdir_all(dest_dir) or { panic(err) }
|
||||
defer { cleanup_test_export(dest_dir) }
|
||||
|
||||
mut client := new(export_dir: test_dir) or { panic(err) }
|
||||
client.copy_images('testcollection', 'page1', dest_dir) or { panic(err) }
|
||||
|
||||
// Should succeed even with no images
|
||||
assert true
|
||||
}
|
||||
|
||||
// Test naming normalization edge cases
|
||||
fn test_naming_normalization_underscores() {
|
||||
test_dir := setup_test_export()
|
||||
defer { cleanup_test_export(test_dir) }
|
||||
|
||||
// Create page with underscores
|
||||
normalized := name_fix_no_underscore_no_ext('test_page_name')
|
||||
os.write_file(os.join_path(test_dir, 'content', 'testcollection', '${normalized}.md'),
|
||||
'# Test') or { panic(err) }
|
||||
|
||||
mut client := new(export_dir: test_dir) or { panic(err) }
|
||||
|
||||
// Should find with underscores
|
||||
exists := client.page_exists('testcollection', 'test_page_name')
|
||||
assert exists == true
|
||||
}
|
||||
|
||||
// Test naming normalization edge cases - dashes
|
||||
fn test_naming_normalization_dashes() {
|
||||
test_dir := setup_test_export()
|
||||
defer { cleanup_test_export(test_dir) }
|
||||
|
||||
// Create page with dashes
|
||||
normalized := name_fix_no_underscore_no_ext('test-page-name')
|
||||
os.write_file(os.join_path(test_dir, 'content', 'testcollection', '${normalized}.md'),
|
||||
'# Test') or { panic(err) }
|
||||
|
||||
mut client := new(export_dir: test_dir) or { panic(err) }
|
||||
|
||||
// Should find with dashes
|
||||
exists := client.page_exists('testcollection', 'test-page-name')
|
||||
assert exists == true
|
||||
}
|
||||
|
||||
// Test naming normalization edge cases - mixed case
|
||||
fn test_naming_normalization_case() {
|
||||
test_dir := setup_test_export()
|
||||
defer { cleanup_test_export(test_dir) }
|
||||
|
||||
// Create page with mixed case
|
||||
normalized := name_fix_no_underscore_no_ext('TestPageName')
|
||||
os.write_file(os.join_path(test_dir, 'content', 'testcollection', '${normalized}.md'),
|
||||
'# Test') or { panic(err) }
|
||||
|
||||
mut client := new(export_dir: test_dir) or { panic(err) }
|
||||
|
||||
// Should find with mixed case
|
||||
exists := client.page_exists('testcollection', 'TestPageName')
|
||||
assert exists == true
|
||||
}
|
||||
169
lib/web/atlas_client/error.v
Normal file
169
lib/web/atlas_client/error.v
Normal file
@@ -0,0 +1,169 @@
|
||||
module atlas_client
|
||||
|
||||
// AtlasErrors represents different types of errors that can occur in AtlasClient
|
||||
pub enum AtlasErrors {
|
||||
collection_not_found
|
||||
page_not_found
|
||||
file_not_found
|
||||
image_not_found
|
||||
export_dir_not_found
|
||||
invalid_export_structure
|
||||
}
|
||||
|
||||
// AtlasError represents an error with a message and a reason
|
||||
struct AtlasError {
|
||||
pub mut:
|
||||
message string // The error message
|
||||
reason AtlasErrors // The reason for the error
|
||||
}
|
||||
|
||||
@[params]
|
||||
struct ErrorArgs {
|
||||
pub mut:
|
||||
message string @[required] // The error message
|
||||
reason AtlasErrors @[required] // The error reason
|
||||
}
|
||||
|
||||
// new_error creates a new AtlasError
|
||||
pub fn new_error(args ErrorArgs) AtlasError {
|
||||
return AtlasError{
|
||||
message: args.message
|
||||
reason: args.reason
|
||||
}
|
||||
}
|
||||
|
||||
// throw_error throws an error with a message and a reason
|
||||
fn (err AtlasError) throw_error(args ErrorArgs) IError {
|
||||
return error('${args.reason}: ${args.message}')
|
||||
}
|
||||
|
||||
// Error helper methods following the same pattern
|
||||
|
||||
@[params]
|
||||
struct CollectionNotFoundArgs {
|
||||
pub mut:
|
||||
collection_name string @[required] // The collection name
|
||||
}
|
||||
|
||||
// error_collection_not_found returns an error for when a collection is not found
|
||||
pub fn (err AtlasError) error_collection_not_found(args CollectionNotFoundArgs) IError {
|
||||
return err.throw_error(
|
||||
message: 'Collection "${args.collection_name}" not found'
|
||||
reason: .collection_not_found
|
||||
)
|
||||
}
|
||||
|
||||
@[params]
|
||||
struct CollectionNotFoundAtArgs {
|
||||
pub mut:
|
||||
collection_name string @[required] // The collection name
|
||||
path string @[required] // The path where metadata was expected
|
||||
}
|
||||
|
||||
// error_collection_not_found_at returns an error for when a collection metadata file is not found
|
||||
pub fn (err AtlasError) error_collection_not_found_at(args CollectionNotFoundAtArgs) IError {
|
||||
return err.throw_error(
|
||||
message: 'Metadata file for collection "${args.collection_name}" not found at "${args.path}"'
|
||||
reason: .collection_not_found
|
||||
)
|
||||
}
|
||||
|
||||
@[params]
|
||||
struct PageNotFoundArgs {
|
||||
pub mut:
|
||||
collection_name string @[required] // The collection name
|
||||
page_name string @[required] // The page name
|
||||
}
|
||||
|
||||
// error_page_not_found returns an error for when a page is not found in a collection
|
||||
pub fn (err AtlasError) error_page_not_found(args PageNotFoundArgs) IError {
|
||||
return err.throw_error(
|
||||
message: 'Page "${args.page_name}" not found in collection "${args.collection_name}"'
|
||||
reason: .page_not_found
|
||||
)
|
||||
}
|
||||
|
||||
// error_page_not_found_in_metadata returns an error for when a page is not found in collection metadata
|
||||
pub fn (err AtlasError) error_page_not_found_in_metadata(args PageNotFoundArgs) IError {
|
||||
return err.throw_error(
|
||||
message: 'Page "${args.page_name}" not found in collection metadata'
|
||||
reason: .page_not_found
|
||||
)
|
||||
}
|
||||
|
||||
@[params]
|
||||
struct PageFileNotExistsArgs {
|
||||
pub mut:
|
||||
page_path string @[required] // The page file path
|
||||
}
|
||||
|
||||
// error_page_file_not_exists returns an error for when a page file doesn't exist on disk
|
||||
pub fn (err AtlasError) error_page_file_not_exists(args PageFileNotExistsArgs) IError {
|
||||
return err.throw_error(
|
||||
message: 'Page file "${args.page_path}" does not exist on disk'
|
||||
reason: .page_not_found
|
||||
)
|
||||
}
|
||||
|
||||
@[params]
|
||||
struct FileNotFoundArgs {
|
||||
pub mut:
|
||||
collection_name string @[required] // The collection name
|
||||
file_name string @[required] // The file name
|
||||
}
|
||||
|
||||
// error_file_not_found returns an error for when a file is not found in a collection
|
||||
pub fn (err AtlasError) error_file_not_found(args FileNotFoundArgs) IError {
|
||||
return err.throw_error(
|
||||
message: 'File "${args.file_name}" not found in collection "${args.collection_name}"'
|
||||
reason: .file_not_found
|
||||
)
|
||||
}
|
||||
|
||||
@[params]
|
||||
struct ImageNotFoundArgs {
|
||||
pub mut:
|
||||
collection_name string @[required] // The collection name
|
||||
image_name string @[required] // The image name
|
||||
}
|
||||
|
||||
// error_image_not_found returns an error for when an image is not found in a collection
|
||||
pub fn (err AtlasError) error_image_not_found(args ImageNotFoundArgs) IError {
|
||||
return err.throw_error(
|
||||
message: 'Image "${args.image_name}" not found in collection "${args.collection_name}"'
|
||||
reason: .image_not_found
|
||||
)
|
||||
}
|
||||
|
||||
// error_image_not_found_linked returns an error for when a linked image is not found
|
||||
pub fn (err AtlasError) error_image_not_found_linked(args ImageNotFoundArgs) IError {
|
||||
return error('Error: Linked image "${args.image_name}" not found in collection "${args.collection_name}".')
|
||||
}
|
||||
|
||||
@[params]
|
||||
struct ExportDirNotFoundArgs {
|
||||
pub mut:
|
||||
export_dir string @[required] // The export directory path
|
||||
}
|
||||
|
||||
// error_export_dir_not_found returns an error for when the export directory doesn't exist
|
||||
pub fn (err AtlasError) error_export_dir_not_found(args ExportDirNotFoundArgs) IError {
|
||||
return err.throw_error(
|
||||
message: 'Export directory "${args.export_dir}" not found'
|
||||
reason: .export_dir_not_found
|
||||
)
|
||||
}
|
||||
|
||||
@[params]
|
||||
struct InvalidExportStructureArgs {
|
||||
pub mut:
|
||||
content_dir string @[required] // The content directory path
|
||||
}
|
||||
|
||||
// error_invalid_export_structure returns an error for when the export directory structure is invalid
|
||||
pub fn (err AtlasError) error_invalid_export_structure(args InvalidExportStructureArgs) IError {
|
||||
return err.throw_error(
|
||||
message: 'Content directory not found at "${args.content_dir}"'
|
||||
reason: .invalid_export_structure
|
||||
)
|
||||
}
|
||||
268
lib/web/atlas_client/error_test.v
Normal file
268
lib/web/atlas_client/error_test.v
Normal file
@@ -0,0 +1,268 @@
|
||||
module atlas_client
|
||||
|
||||
// Test error_collection_not_found
|
||||
fn test_error_collection_not_found() {
|
||||
err_handler := AtlasError{}
|
||||
result := err_handler.error_collection_not_found(collection_name: 'test_collection')
|
||||
|
||||
assert result.msg().contains('collection_not_found')
|
||||
assert result.msg().contains('test_collection')
|
||||
assert result.msg().contains('Collection')
|
||||
assert result.msg().contains('not found')
|
||||
}
|
||||
|
||||
// Test error_collection_not_found with special characters
|
||||
fn test_error_collection_not_found_special_chars() {
|
||||
err_handler := AtlasError{}
|
||||
result := err_handler.error_collection_not_found(collection_name: 'test-collection_123')
|
||||
|
||||
assert result.msg().contains('test-collection_123')
|
||||
}
|
||||
|
||||
// Test error_collection_not_found with empty string
|
||||
fn test_error_collection_not_found_empty() {
|
||||
err_handler := AtlasError{}
|
||||
result := err_handler.error_collection_not_found(collection_name: '')
|
||||
|
||||
assert result.msg().contains('collection_not_found')
|
||||
}
|
||||
|
||||
// Test error_collection_not_found_at
|
||||
fn test_error_collection_not_found_at() {
|
||||
err_handler := AtlasError{}
|
||||
result := err_handler.error_collection_not_found_at(
|
||||
collection_name: 'my_collection'
|
||||
path: '/tmp/meta/my_collection.json'
|
||||
)
|
||||
|
||||
assert result.msg().contains('collection_not_found')
|
||||
assert result.msg().contains('my_collection')
|
||||
assert result.msg().contains('/tmp/meta/my_collection.json')
|
||||
assert result.msg().contains('Metadata file')
|
||||
}
|
||||
|
||||
// Test error_page_not_found
|
||||
fn test_error_page_not_found() {
|
||||
err_handler := AtlasError{}
|
||||
result := err_handler.error_page_not_found(
|
||||
collection_name: 'docs'
|
||||
page_name: 'intro'
|
||||
)
|
||||
|
||||
assert result.msg().contains('page_not_found')
|
||||
assert result.msg().contains('docs')
|
||||
assert result.msg().contains('intro')
|
||||
assert result.msg().contains('Page')
|
||||
}
|
||||
|
||||
// Test error_page_not_found with underscores and dashes
|
||||
fn test_error_page_not_found_naming() {
|
||||
err_handler := AtlasError{}
|
||||
result := err_handler.error_page_not_found(
|
||||
collection_name: 'my-docs_v2'
|
||||
page_name: 'getting_started'
|
||||
)
|
||||
|
||||
assert result.msg().contains('my-docs_v2')
|
||||
assert result.msg().contains('getting_started')
|
||||
}
|
||||
|
||||
// Test error_page_not_found_in_metadata
|
||||
fn test_error_page_not_found_in_metadata() {
|
||||
err_handler := AtlasError{}
|
||||
result := err_handler.error_page_not_found_in_metadata(
|
||||
collection_name: 'api'
|
||||
page_name: 'endpoints'
|
||||
)
|
||||
|
||||
assert result.msg().contains('page_not_found')
|
||||
assert result.msg().contains('endpoints')
|
||||
assert result.msg().contains('metadata')
|
||||
}
|
||||
|
||||
// Test error_page_file_not_exists
|
||||
fn test_error_page_file_not_exists() {
|
||||
err_handler := AtlasError{}
|
||||
result := err_handler.error_page_file_not_exists(
|
||||
page_path: '/tmp/content/docs/page.md'
|
||||
)
|
||||
|
||||
assert result.msg().contains('page_not_found')
|
||||
assert result.msg().contains('/tmp/content/docs/page.md')
|
||||
assert result.msg().contains('does not exist')
|
||||
}
|
||||
|
||||
// Test error_file_not_found
|
||||
fn test_error_file_not_found() {
|
||||
err_handler := AtlasError{}
|
||||
result := err_handler.error_file_not_found(
|
||||
collection_name: 'resources'
|
||||
file_name: 'data.csv'
|
||||
)
|
||||
|
||||
assert result.msg().contains('file_not_found')
|
||||
assert result.msg().contains('resources')
|
||||
assert result.msg().contains('data.csv')
|
||||
assert result.msg().contains('File')
|
||||
}
|
||||
|
||||
// Test error_file_not_found with various extensions
|
||||
fn test_error_file_not_found_extensions() {
|
||||
err_handler := AtlasError{}
|
||||
|
||||
// Test PDF
|
||||
result1 := err_handler.error_file_not_found(
|
||||
collection_name: 'docs'
|
||||
file_name: 'manual.pdf'
|
||||
)
|
||||
assert result1.msg().contains('manual.pdf')
|
||||
|
||||
// Test JSON
|
||||
result2 := err_handler.error_file_not_found(
|
||||
collection_name: 'config'
|
||||
file_name: 'settings.json'
|
||||
)
|
||||
assert result2.msg().contains('settings.json')
|
||||
}
|
||||
|
||||
// Test error_image_not_found
|
||||
fn test_error_image_not_found() {
|
||||
err_handler := AtlasError{}
|
||||
result := err_handler.error_image_not_found(
|
||||
collection_name: 'gallery'
|
||||
image_name: 'logo.png'
|
||||
)
|
||||
|
||||
assert result.msg().contains('image_not_found')
|
||||
assert result.msg().contains('gallery')
|
||||
assert result.msg().contains('logo.png')
|
||||
assert result.msg().contains('Image')
|
||||
}
|
||||
|
||||
// Test error_image_not_found with various image formats
|
||||
fn test_error_image_not_found_formats() {
|
||||
err_handler := AtlasError{}
|
||||
|
||||
formats := ['logo.png', 'banner.jpg', 'icon.svg', 'photo.webp', 'diagram.gif']
|
||||
for format in formats {
|
||||
result := err_handler.error_image_not_found(
|
||||
collection_name: 'images'
|
||||
image_name: format
|
||||
)
|
||||
assert result.msg().contains(format)
|
||||
}
|
||||
}
|
||||
|
||||
// Test error_image_not_found_linked
|
||||
fn test_error_image_not_found_linked() {
|
||||
err_handler := AtlasError{}
|
||||
result := err_handler.error_image_not_found_linked(
|
||||
collection_name: 'blog'
|
||||
image_name: 'header.jpg'
|
||||
)
|
||||
|
||||
assert result.msg().contains('Linked image')
|
||||
assert result.msg().contains('blog')
|
||||
assert result.msg().contains('header.jpg')
|
||||
}
|
||||
|
||||
// Test error_export_dir_not_found
|
||||
fn test_error_export_dir_not_found() {
|
||||
err_handler := AtlasError{}
|
||||
result := err_handler.error_export_dir_not_found(
|
||||
export_dir: '/nonexistent/path'
|
||||
)
|
||||
|
||||
assert result.msg().contains('export_dir_not_found')
|
||||
assert result.msg().contains('/nonexistent/path')
|
||||
assert result.msg().contains('Export directory')
|
||||
}
|
||||
|
||||
// Test error_invalid_export_structure
|
||||
fn test_error_invalid_export_structure() {
|
||||
err_handler := AtlasError{}
|
||||
result := err_handler.error_invalid_export_structure(
|
||||
content_dir: '/tmp/export/content'
|
||||
)
|
||||
|
||||
assert result.msg().contains('invalid_export_structure')
|
||||
assert result.msg().contains('/tmp/export/content')
|
||||
assert result.msg().contains('Content directory')
|
||||
}
|
||||
|
||||
// Test new_error function
|
||||
fn test_new_error() {
|
||||
err := new_error(
|
||||
message: 'Test error message'
|
||||
reason: .page_not_found
|
||||
)
|
||||
|
||||
assert err.message == 'Test error message'
|
||||
assert err.reason == .page_not_found
|
||||
}
|
||||
|
||||
// Test new_error with all error types
|
||||
fn test_new_error_all_types() {
|
||||
error_types := [
|
||||
AtlasErrors.collection_not_found,
|
||||
AtlasErrors.page_not_found,
|
||||
AtlasErrors.file_not_found,
|
||||
AtlasErrors.image_not_found,
|
||||
AtlasErrors.export_dir_not_found,
|
||||
AtlasErrors.invalid_export_structure,
|
||||
]
|
||||
|
||||
for error_type in error_types {
|
||||
err := new_error(
|
||||
message: 'Test message'
|
||||
reason: error_type
|
||||
)
|
||||
assert err.reason == error_type
|
||||
}
|
||||
}
|
||||
|
||||
// Test throw_error internal method
|
||||
fn test_throw_error() {
|
||||
err_handler := AtlasError{}
|
||||
result := err_handler.throw_error(
|
||||
message: 'Custom error message'
|
||||
reason: .file_not_found
|
||||
)
|
||||
|
||||
assert result.msg().contains('file_not_found')
|
||||
assert result.msg().contains('Custom error message')
|
||||
}
|
||||
|
||||
// Test error messages are properly formatted
|
||||
fn test_error_message_format() {
|
||||
err_handler := AtlasError{}
|
||||
|
||||
// Test that error messages follow the pattern: "reason: message"
|
||||
result := err_handler.error_page_not_found(
|
||||
collection_name: 'test'
|
||||
page_name: 'page'
|
||||
)
|
||||
|
||||
msg := result.msg()
|
||||
assert msg.contains(':')
|
||||
|
||||
// Split by colon and verify format
|
||||
parts := msg.split(':')
|
||||
assert parts.len >= 2
|
||||
}
|
||||
|
||||
// Test error consistency across similar methods
|
||||
fn test_error_consistency() {
|
||||
err_handler := AtlasError{}
|
||||
|
||||
// All "not found" errors should contain "not found" in message
|
||||
err1 := err_handler.error_collection_not_found(collection_name: 'test')
|
||||
err2 := err_handler.error_page_not_found(collection_name: 'test', page_name: 'page')
|
||||
err3 := err_handler.error_file_not_found(collection_name: 'test', file_name: 'file')
|
||||
err4 := err_handler.error_image_not_found(collection_name: 'test', image_name: 'img')
|
||||
|
||||
assert err1.msg().contains('not found')
|
||||
assert err2.msg().contains('not found')
|
||||
assert err3.msg().contains('not found')
|
||||
assert err4.msg().contains('not found')
|
||||
}
|
||||
55
lib/web/atlas_client/extract_links.v
Normal file
55
lib/web/atlas_client/extract_links.v
Normal file
@@ -0,0 +1,55 @@
|
||||
module atlas_client
|
||||
|
||||
import os
|
||||
|
||||
// extract_image_links extracts image file names from markdown content
|
||||
// If exclude_http is true, it will skip images with http:// or https:// URLs
|
||||
pub fn extract_image_links(s string, exclude_http bool) ![]string {
|
||||
mut result := []string{}
|
||||
mut current_pos := 0
|
||||
for {
|
||||
if current_pos >= s.len {
|
||||
break
|
||||
}
|
||||
|
||||
// Find the start of an image markdown link
|
||||
start_index := s.index_after('![', current_pos) or { -1 }
|
||||
if start_index == -1 {
|
||||
break // No more image links found
|
||||
}
|
||||
|
||||
// Find the closing bracket for alt text
|
||||
alt_end_index := s.index_after(']', start_index) or { -1 }
|
||||
if alt_end_index == -1 {
|
||||
break
|
||||
}
|
||||
|
||||
// Check for opening parenthesis for URL
|
||||
if alt_end_index + 1 >= s.len || s[alt_end_index + 1] != `(` {
|
||||
current_pos = alt_end_index + 1 // Move past this invalid sequence
|
||||
continue
|
||||
}
|
||||
|
||||
// Find the closing parenthesis for URL
|
||||
url_start_index := alt_end_index + 2
|
||||
url_end_index := s.index_after(')', url_start_index) or { -1 }
|
||||
if url_end_index == -1 {
|
||||
break
|
||||
}
|
||||
|
||||
// Extract the URL
|
||||
url := s[url_start_index..url_end_index]
|
||||
if exclude_http && (url.starts_with('http://') || url.starts_with('https://')) {
|
||||
current_pos = url_end_index + 1
|
||||
continue
|
||||
}
|
||||
|
||||
// Extract only the base name of the image from the URL
|
||||
image_base_name := os.base(url)
|
||||
result << image_base_name
|
||||
|
||||
// Move current_pos past the found link to continue searching
|
||||
current_pos = url_end_index + 1
|
||||
}
|
||||
return result
|
||||
}
|
||||
298
lib/web/atlas_client/extract_links_test.v
Normal file
298
lib/web/atlas_client/extract_links_test.v
Normal file
@@ -0,0 +1,298 @@
|
||||
module atlas_client
|
||||
|
||||
// Test basic image link extraction
|
||||
fn test_extract_image_links_basic() {
|
||||
content := ''
|
||||
result := extract_image_links(content, false) or { panic(err) }
|
||||
|
||||
assert result.len == 1
|
||||
assert result[0] == 'image.png'
|
||||
}
|
||||
|
||||
// Test multiple image links
|
||||
fn test_extract_image_links_multiple() {
|
||||
content := ' some text  more text '
|
||||
result := extract_image_links(content, false) or { panic(err) }
|
||||
|
||||
assert result.len == 3
|
||||
assert result[0] == 'logo.png'
|
||||
assert result[1] == 'banner.jpg'
|
||||
assert result[2] == 'icon.svg'
|
||||
}
|
||||
|
||||
// Test empty content
|
||||
fn test_extract_image_links_empty() {
|
||||
content := ''
|
||||
result := extract_image_links(content, false) or { panic(err) }
|
||||
|
||||
assert result.len == 0
|
||||
}
|
||||
|
||||
// Test content with no images
|
||||
fn test_extract_image_links_no_images() {
|
||||
content := 'This is just plain text with no images'
|
||||
result := extract_image_links(content, false) or { panic(err) }
|
||||
|
||||
assert result.len == 0
|
||||
}
|
||||
|
||||
// Test content with regular links (not images)
|
||||
fn test_extract_image_links_regular_links() {
|
||||
content := '[regular link](page.md) and [another](doc.html)'
|
||||
result := extract_image_links(content, false) or { panic(err) }
|
||||
|
||||
assert result.len == 0
|
||||
}
|
||||
|
||||
// Test HTTP URLs with exclude_http = true
|
||||
fn test_extract_image_links_exclude_http() {
|
||||
content := '  '
|
||||
result := extract_image_links(content, true) or { panic(err) }
|
||||
|
||||
assert result.len == 1
|
||||
assert result[0] == 'local.png'
|
||||
}
|
||||
|
||||
// Test HTTP URLs with exclude_http = false
|
||||
fn test_extract_image_links_include_http() {
|
||||
content := '  '
|
||||
result := extract_image_links(content, false) or { panic(err) }
|
||||
|
||||
assert result.len == 3
|
||||
assert result[0] == 'local.png'
|
||||
assert result[1] == 'image.jpg'
|
||||
assert result[2] == 'logo.png'
|
||||
}
|
||||
|
||||
// Test image paths with directories
|
||||
fn test_extract_image_links_with_paths() {
|
||||
content := '  '
|
||||
result := extract_image_links(content, false) or { panic(err) }
|
||||
|
||||
assert result.len == 3
|
||||
assert result[0] == 'logo.png'
|
||||
assert result[1] == 'banner.jpg'
|
||||
assert result[2] == 'icon.svg'
|
||||
}
|
||||
|
||||
// Test various image formats
|
||||
fn test_extract_image_links_formats() {
|
||||
content := '      '
|
||||
result := extract_image_links(content, false) or { panic(err) }
|
||||
|
||||
assert result.len == 7
|
||||
assert 'img.png' in result
|
||||
assert 'img.jpg' in result
|
||||
assert 'img.jpeg' in result
|
||||
assert 'img.gif' in result
|
||||
assert 'img.svg' in result
|
||||
assert 'img.webp' in result
|
||||
assert 'img.bmp' in result
|
||||
}
|
||||
|
||||
// Test malformed markdown - missing closing bracket
|
||||
fn test_extract_image_links_malformed_no_closing_bracket() {
|
||||
content := '![alt text(image.png)'
|
||||
result := extract_image_links(content, false) or { panic(err) }
|
||||
|
||||
assert result.len == 0
|
||||
}
|
||||
|
||||
// Test malformed markdown - missing opening parenthesis
|
||||
fn test_extract_image_links_malformed_no_paren() {
|
||||
content := '![alt text]image.png)'
|
||||
result := extract_image_links(content, false) or { panic(err) }
|
||||
|
||||
assert result.len == 0
|
||||
}
|
||||
|
||||
// Test malformed markdown - missing closing parenthesis
|
||||
fn test_extract_image_links_malformed_no_closing_paren() {
|
||||
content := ' or { panic(err) }
|
||||
|
||||
assert result.len == 0
|
||||
}
|
||||
|
||||
// Test empty alt text
|
||||
fn test_extract_image_links_empty_alt() {
|
||||
content := ''
|
||||
result := extract_image_links(content, false) or { panic(err) }
|
||||
|
||||
assert result.len == 1
|
||||
assert result[0] == 'image.png'
|
||||
}
|
||||
|
||||
// Test alt text with special characters
|
||||
fn test_extract_image_links_special_alt() {
|
||||
content := ''
|
||||
result := extract_image_links(content, false) or { panic(err) }
|
||||
|
||||
assert result.len == 1
|
||||
assert result[0] == 'logo.png'
|
||||
}
|
||||
|
||||
// Test image names with special characters
|
||||
fn test_extract_image_links_special_names() {
|
||||
content := '  '
|
||||
result := extract_image_links(content, false) or { panic(err) }
|
||||
|
||||
assert result.len == 3
|
||||
assert result[0] == 'logo-2024.png'
|
||||
assert result[1] == 'banner_v2.jpg'
|
||||
assert result[2] == 'icon.final.svg'
|
||||
}
|
||||
|
||||
// Test mixed content with text, links, and images
|
||||
fn test_extract_image_links_mixed_content() {
|
||||
content := '
|
||||
# Header
|
||||
|
||||
Some text with [a link](page.md) and an image .
|
||||
|
||||
## Section
|
||||
|
||||
More text and  another image.
|
||||
|
||||
[Another link](doc.html)
|
||||
|
||||

|
||||
'
|
||||
result := extract_image_links(content, false) or { panic(err) }
|
||||
|
||||
assert result.len == 3
|
||||
assert result[0] == 'logo.png'
|
||||
assert result[1] == 'banner.jpg'
|
||||
assert result[2] == 'icon.svg'
|
||||
}
|
||||
|
||||
// Test consecutive images
|
||||
fn test_extract_image_links_consecutive() {
|
||||
content := ''
|
||||
result := extract_image_links(content, false) or { panic(err) }
|
||||
|
||||
assert result.len == 3
|
||||
assert result[0] == 'a.png'
|
||||
assert result[1] == 'b.jpg'
|
||||
assert result[2] == 'c.svg'
|
||||
}
|
||||
|
||||
// Test images with query parameters
|
||||
fn test_extract_image_links_query_params() {
|
||||
content := ''
|
||||
result := extract_image_links(content, false) or { panic(err) }
|
||||
|
||||
assert result.len == 1
|
||||
// Should extract the full filename including query params
|
||||
assert result[0].contains('image.png')
|
||||
}
|
||||
|
||||
// Test images with anchors
|
||||
fn test_extract_image_links_anchors() {
|
||||
content := ''
|
||||
result := extract_image_links(content, false) or { panic(err) }
|
||||
|
||||
assert result.len == 1
|
||||
assert result[0].contains('image.png')
|
||||
}
|
||||
|
||||
// Test duplicate images
|
||||
fn test_extract_image_links_duplicates() {
|
||||
content := ' some text  more text '
|
||||
result := extract_image_links(content, false) or { panic(err) }
|
||||
|
||||
assert result.len == 3
|
||||
assert result[0] == 'logo.png'
|
||||
assert result[1] == 'logo.png'
|
||||
assert result[2] == 'logo.png'
|
||||
}
|
||||
|
||||
// Test very long content
|
||||
fn test_extract_image_links_long_content() {
|
||||
mut content := ''
|
||||
for i in 0 .. 100 {
|
||||
content += 'Some text here. '
|
||||
if i % 10 == 0 {
|
||||
content += ' '
|
||||
}
|
||||
}
|
||||
|
||||
result := extract_image_links(content, false) or { panic(err) }
|
||||
assert result.len == 10
|
||||
}
|
||||
|
||||
// Test image with absolute path
|
||||
fn test_extract_image_links_absolute_path() {
|
||||
content := ''
|
||||
result := extract_image_links(content, false) or { panic(err) }
|
||||
|
||||
assert result.len == 1
|
||||
assert result[0] == 'image.png'
|
||||
}
|
||||
|
||||
// Test image with Windows-style path
|
||||
fn test_extract_image_links_windows_path() {
|
||||
content := ''
|
||||
result := extract_image_links(content, false) or { panic(err) }
|
||||
|
||||
assert result.len == 1
|
||||
assert result[0] == 'logo.png'
|
||||
}
|
||||
|
||||
// Test nested brackets in alt text
|
||||
fn test_extract_image_links_nested_brackets() {
|
||||
content := '![alt [with] brackets](image.png)'
|
||||
result := extract_image_links(content, false) or { panic(err) }
|
||||
|
||||
// This might not work correctly due to nested brackets
|
||||
// The function should handle it gracefully
|
||||
assert result.len >= 0
|
||||
}
|
||||
|
||||
// Test image link at start of string
|
||||
fn test_extract_image_links_at_start() {
|
||||
content := ' followed by text'
|
||||
result := extract_image_links(content, false) or { panic(err) }
|
||||
|
||||
assert result.len == 1
|
||||
assert result[0] == 'logo.png'
|
||||
}
|
||||
|
||||
// Test image link at end of string
|
||||
fn test_extract_image_links_at_end() {
|
||||
content := 'text followed by '
|
||||
result := extract_image_links(content, false) or { panic(err) }
|
||||
|
||||
assert result.len == 1
|
||||
assert result[0] == 'logo.png'
|
||||
}
|
||||
|
||||
// Test only image link
|
||||
fn test_extract_image_links_only() {
|
||||
content := ''
|
||||
result := extract_image_links(content, false) or { panic(err) }
|
||||
|
||||
assert result.len == 1
|
||||
assert result[0] == 'logo.png'
|
||||
}
|
||||
|
||||
// Test whitespace in URL
|
||||
fn test_extract_image_links_whitespace() {
|
||||
content := ''
|
||||
result := extract_image_links(content, false) or { panic(err) }
|
||||
|
||||
assert result.len == 1
|
||||
// Should preserve whitespace as-is
|
||||
assert result[0].contains('image.png')
|
||||
}
|
||||
|
||||
// Test case sensitivity
|
||||
fn test_extract_image_links_case_sensitivity() {
|
||||
content := '  '
|
||||
result := extract_image_links(content, false) or { panic(err) }
|
||||
|
||||
assert result.len == 3
|
||||
assert result[0] == 'Image.PNG'
|
||||
assert result[1] == 'LOGO.jpg'
|
||||
assert result[2] == 'banner.SVG'
|
||||
}
|
||||
22
lib/web/atlas_client/factory.v
Normal file
22
lib/web/atlas_client/factory.v
Normal file
@@ -0,0 +1,22 @@
|
||||
module atlas_client
|
||||
|
||||
import incubaid.herolib.core.base
|
||||
|
||||
@[params]
|
||||
pub struct AtlasClientArgs {
|
||||
pub:
|
||||
export_dir string @[required] // Path to atlas export directory
|
||||
}
|
||||
|
||||
// Create a new AtlasClient instance
|
||||
// The export_dir should point to the directory containing content/ and meta/ subdirectories
|
||||
pub fn new(args AtlasClientArgs) !&AtlasClient {
|
||||
mut context := base.context()!
|
||||
mut redis := context.redis()!
|
||||
|
||||
return &AtlasClient{
|
||||
AtlasError: AtlasError{}
|
||||
redis: redis
|
||||
export_dir: args.export_dir
|
||||
}
|
||||
}
|
||||
12
lib/web/atlas_client/model.v
Normal file
12
lib/web/atlas_client/model.v
Normal file
@@ -0,0 +1,12 @@
|
||||
module atlas_client
|
||||
|
||||
import incubaid.herolib.core.redisclient
|
||||
|
||||
// AtlasClient provides access to Atlas-exported documentation collections
|
||||
// It reads from both the exported directory structure and Redis metadata
|
||||
pub struct AtlasClient {
|
||||
AtlasError // Embedded error handler for generating standardized errors
|
||||
pub mut:
|
||||
redis &redisclient.Redis
|
||||
export_dir string // Path to the atlas export directory (contains content/ and meta/)
|
||||
}
|
||||
Reference in New Issue
Block a user