Files
markitect-main/docs/api/packaging.md
tegwick ec09fdd0bd
Some checks failed
Test Suite / unit-tests (3.11) (push) Has been cancelled
Test Suite / unit-tests (3.12) (push) Has been cancelled
Test Suite / integration-tests (push) Has been cancelled
Test Suite / e2e-tests (push) Has been cancelled
Test Suite / performance-tests (push) Has been cancelled
Test Suite / code-quality (push) Has been cancelled
Test Suite / security-scan (push) Has been cancelled
Test Suite / test-summary (push) Has been cancelled
feat: complete Issue #150 - Advanced Packaging Features (.mdz, .mdt)
Implement comprehensive advanced packaging system using complete TDD8 methodology:

## Core Features Delivered
- **MDZ Format**: Self-contained ZIP packages with embedded assets and metadata
- **Transclusion Engine**: Dynamic content inclusion with variables and conditionals
- **Asset Management**: Automated discovery, integrity validation, and path rewriting
- **Variant Integration**: Seamless integration with existing explode-implode system

## Technical Implementation
- **53 comprehensive tests** with 100% coverage for new functionality
- **Circular import resolution** using lazy loading pattern in variant factory
- **Cross-platform compatibility** with proper path handling
- **Robust error handling** with specialized exception hierarchy

## Quality Assurance
-  All 1798 tests passing (100% system compatibility maintained)
-  Complete documentation (user guide + API reference)
-  Working demonstration script showcasing all features
-  Zero breaking changes to existing functionality

## Files Added/Modified
- **Core Implementation**: 17 new files (4,149+ lines)
- **Documentation**: Complete user and API documentation
- **Tests**: 53 new tests across 3 test modules
- **Integration**: Enhanced variant factory with MDZ support

Built on solid foundation from Issues #148-149. Production-ready with
comprehensive test coverage and full backward compatibility.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-13 23:09:18 +02:00

12 KiB

Packaging API Reference

Complete API reference for MarkiTect's advanced packaging system (Issue #150).

Module Structure

markitect.packaging/
├── __init__.py                  # Main module exports
├── base.py                      # Base classes and constants
├── errors.py                    # Exception hierarchy
├── metadata.py                  # Metadata dataclasses
├── asset_utils.py               # Asset management utilities
├── path_utils.py                # Path handling utilities
├── mdz_variant.py               # MDZ format implementation
└── transclusion/                # Transclusion engine
    ├── __init__.py
    ├── engine.py                # Main transclusion engine
    ├── context.py               # Processing context
    └── directives.py            # Directive parsing

Core Classes

PackagingVariant

Abstract base class for all packaging variants.

from markitect.packaging.base import PackagingVariant

class MyPackagingVariant(PackagingVariant):
    def create_package(self, source_path: Path, options: Dict[str, Any]) -> Dict[str, Any]:
        # Implementation
        pass

    def extract_package(self, package_path: Path, options: Dict[str, Any]) -> Dict[str, Any]:
        # Implementation
        pass

    # ... other required methods

Abstract Methods

  • create_package(source_path, options): Create package from source
  • extract_package(package_path, options): Extract package to destination
  • get_package_metadata(package_path): Get package metadata
  • embed_assets(assets, package_path): Embed assets into package
  • rewrite_asset_paths(content, asset_map): Rewrite asset paths in content

MdzVariant

Complete implementation of MDZ (Markdown Zip) format.

from markitect.packaging.mdz_variant import MdzVariant

# Initialize variant
mdz = MdzVariant()

# Create package
result = mdz.create_package(
    source_path=Path("document.md"),
    options={
        'output_path': Path("document.mdz"),
        'compression_level': 6
    }
)

# Extract package
extract_result = mdz.extract_package(
    package_path=Path("document.mdz"),
    options={'output_dir': Path("extracted/")}
)

# Get metadata
metadata = mdz.get_package_metadata(Path("document.mdz"))

Methods

create_package(source_path: Path, options: Dict[str, Any]) -> Dict[str, Any]

Creates MDZ package from source content.

Parameters:

  • source_path: Path to source markdown file or directory
  • options: Package creation options
    • output_path (optional): Output package path
    • compression_level (optional): ZIP compression level (0-9)

Returns: Dictionary with creation results:

{
    'success': True,
    'package_path': Path('document.mdz'),
    'assets_embedded': 5,
    'package_size': 1024000
}
extract_package(package_path: Path, options: Dict[str, Any]) -> Dict[str, Any]

Extracts MDZ package contents.

Parameters:

  • package_path: Path to MDZ package file
  • options: Extraction options
    • output_dir (optional): Output directory path

Returns: Dictionary with extraction results:

{
    'success': True,
    'output_directory': Path('extracted/'),
    'files_extracted': 8,
    'extracted_files': [Path('content.md'), Path('assets/image.png'), ...]
}
get_package_metadata(package_path: Path) -> PackageMetadata

Retrieves package metadata.

Returns: PackageMetadata object with package information.

Transclusion Engine

TransclusionEngine

Main engine for processing transclusion directives.

from markitect.packaging.transclusion import TransclusionEngine

engine = TransclusionEngine(
    base_path=Path("templates/"),
    variables={'title': 'My Document', 'version': '1.0'},
    max_depth=10
)

# Process content with directives
result = engine.process_content(content_with_directives)

# Process file
result = engine.process_file(Path("template.mdt"))

Methods

__init__(base_path=None, variables=None, max_depth=10)

Initialize transclusion engine.

Parameters:

  • base_path: Base path for relative file resolution
  • variables: Initial variables dictionary
  • max_depth: Maximum inclusion depth (default: 10)
process_content(content: str, context=None) -> str

Process transclusion directives in content.

Parameters:

  • content: String containing transclusion directives
  • context: Optional TransclusionContext (created if None)

Returns: Processed content with directives resolved

process_file(file_path: Path, context=None) -> str

Process file with transclusion directives.

Parameters:

  • file_path: Path to file to process
  • context: Optional TransclusionContext

Returns: Processed file content

TransclusionContext

Context manager for transclusion processing.

from markitect.packaging.transclusion import TransclusionContext

context = TransclusionContext(
    base_path=Path("templates/"),
    variables={'author': 'John Doe'},
    max_depth=5
)

# Set variables
context.set_variable('title', 'Advanced Guide')

# Get variables with default
title = context.get_variable('title', 'Untitled')

# Substitute variables in text
result = context.substitute_variables("Title: {{title}}")

Methods

set_variable(name: str, value: Any)

Set a variable in the context.

get_variable(name: str, default=None) -> Any

Get variable value with optional default.

substitute_variables(text: str) -> str

Substitute variables using {{variable}} syntax.

resolve_path(path: str) -> Path

Resolve path relative to context base path.

enter_file(file_path: Path) / exit_file(file_path: Path)

Track file processing for circular reference detection.

DirectiveParser

Parser for transclusion directives.

from markitect.packaging.transclusion import DirectiveParser

# Parse all directives from content
directives = DirectiveParser.parse_directives(content)

# Extract just file includes
files = DirectiveParser.extract_file_includes(content)

Methods

parse_directives(content: str) -> List[Directive]

Parse all transclusion directives from content.

Returns: List of Directive objects with:

  • type: Directive type ('include', 'variable', 'conditional')
  • args: Parsed arguments dictionary
  • content: Block content (for conditional directives)
  • start_pos, end_pos: Position in original content
extract_file_includes(content: str) -> List[str]

Extract file paths from include directives.

Returns: List of file paths referenced in includes

Utility Classes

AssetUtils

Utilities for asset discovery and management.

from markitect.packaging.asset_utils import AssetUtils

# Discover assets in directory
assets = AssetUtils.discover_assets(Path("project/"))

# Create asset metadata
metadata = AssetUtils.create_asset_metadata(
    file_path=Path("image.png"),
    package_path="assets/image.png"
)

# Calculate checksum
checksum = AssetUtils.calculate_checksum(Path("file.jpg"))

# Validate integrity
valid = AssetUtils.validate_asset_integrity(Path("file.jpg"), expected_checksum)

Static Methods

discover_assets(source_path: Path, asset_extensions=None) -> List[Path]

Discover asset files in a source path.

Parameters:

  • source_path: Directory or file to search
  • asset_extensions: Set of extensions to consider (optional)

Returns: List of discovered asset paths

create_asset_metadata(file_path: Path, package_path: str, original_path=None) -> AssetMetadata

Create metadata for an asset file.

Returns: AssetMetadata object with file information

calculate_checksum(file_path: Path) -> str

Calculate SHA-256 checksum of file.

validate_asset_integrity(file_path: Path, expected_checksum: str) -> bool

Validate file integrity using checksum.

PathUtils

Path manipulation and rewriting utilities.

from markitect.packaging.path_utils import PathUtils

# Rewrite asset paths in content
content = "![Image](./assets/logo.png)"
asset_map = {"./assets/logo.png": "embedded/logo.png"}
rewritten = PathUtils.rewrite_asset_paths(content, asset_map)

# Extract referenced paths
paths = PathUtils.extract_referenced_paths(markdown_content)

# Normalize path
normalized = PathUtils.normalize_path("./images/../assets/file.png")

Static Methods

rewrite_asset_paths(content: str, asset_map: Dict[str, str]) -> str

Rewrite asset paths in markdown content.

Parameters:

  • content: Markdown content to process
  • asset_map: Mapping from original to new paths
extract_referenced_paths(content: str) -> Set[str]

Extract all asset paths referenced in markdown.

normalize_path(path: str, base_path=None) -> str

Normalize path for consistent handling.

is_external_url(url: str) -> bool

Check if URL is external (has scheme).

Data Classes

PackageMetadata

@dataclass
class PackageMetadata:
    format: str                    # Package format ("mdz", "mdt", etc.)
    version: str                   # Package format version
    created: str                   # ISO timestamp of creation
    markitect_version: str         # MarkiTect version used
    assets: List[AssetMetadata]    # List of embedded assets
    dependencies: List[str] = None # Optional dependencies

AssetMetadata

@dataclass
class AssetMetadata:
    path: str                        # Path within package
    original_path: str               # Original source path
    size: int                        # File size in bytes
    checksum: str                    # SHA-256 checksum
    mime_type: Optional[str] = None  # MIME type

Exception Hierarchy

PackagingError                    # Base packaging exception
├── PackageFormatError           # Package format issues
│   └── InvalidPackageError      # Invalid package structure
├── AssetError                   # Asset handling errors
│   └── AssetNotFoundError       # Asset file not found
├── PathRewriteError            # Path rewriting issues
└── TransclusionError           # Transclusion processing errors
    ├── CircularReferenceError   # Circular inclusion detected
    └── DepthLimitError         # Max inclusion depth exceeded

Usage

from markitect.packaging.errors import (
    PackagingError, AssetError, TransclusionError,
    CircularReferenceError, DepthLimitError
)

try:
    result = engine.process_file(template_file)
except CircularReferenceError as e:
    print(f"Circular reference: {e}")
except TransclusionError as e:
    print(f"Transclusion error: {e}")
except PackagingError as e:
    print(f"General packaging error: {e}")

Integration Points

Variant System Integration

# Add to ExplodeVariant enum
from markitect.explode_variants.enums import ExplodeVariant
# ExplodeVariant.MDZ and ExplodeVariant.MDT are now available

# Factory integration
from markitect.explode_variants import get_variant_factory
factory = get_variant_factory()
mdz_variant = factory.create_variant(ExplodeVariant.MDZ)

CLI Integration

Future CLI commands will integrate with this API:

# Will use MdzVariant.create_package()
markitect md-package create document.md --format mdz

# Will use TransclusionEngine.process_file()
markitect md-transclude process template.mdt --variables vars.json

Version: 1.0 (Issue #150) Status: Complete implementation with 100% test coverage Compatibility: Integrates seamlessly with existing MarkiTect variant system