TypeDialog/docs/fragment-search-paths.md
2025-12-26 23:24:53 +00:00

8.3 KiB

Fragment Search Paths

TypeDialog supports loading form fragments from multiple directories using the TYPEDIALOG_FRAGMENT_PATH environment variable.

Overview

Fragment search paths enable:

  • Centralized fragment libraries shared across projects
  • Local overrides for project-specific customizations
  • Zero duplication when using standard fragments
  • Automatic updates when central library is updated

Environment Variable

TYPEDIALOG_FRAGMENT_PATH

Colon-separated list (semicolon on Windows) of directories to search for fragment files.

Unix/Linux/macOS:

export TYPEDIALOG_FRAGMENT_PATH="/path/to/fragments:/another/path"

Windows:

set TYPEDIALOG_FRAGMENT_PATH=C:\fragments;D:\other\fragments

Search Order

When a fragment is referenced (e.g., includes = ["fragments/user-fields.toml"]), TypeDialog searches in this order:

  1. Absolute path → Use directly if provided
  2. Form's directory (base_dir) → Backward compatible behavior
  3. Directories in TYPEDIALOG_FRAGMENT_PATH → Search left to right
  4. First match wins → Subsequent directories are not checked

Example

export TYPEDIALOG_FRAGMENT_PATH=".typedialog/ci/fragments:/usr/local/share/typedialog/fragments"

Fragment reference: includes = ["user-auth.toml"]

Search order:

1. ./user-auth.toml (form's directory)
2. .typedialog/ci/fragments/user-auth.toml (local)
3. /usr/local/share/typedialog/fragments/user-auth.toml (system)

Result: First existing file is loaded.

Use Cases

Case 1: Centralized Fragment Library

Organization maintains a shared library of standard fragments.

Setup:

# System-wide fragments
export TYPEDIALOG_FRAGMENT_PATH="/opt/company/typedialog/fragments"

Directory structure:

/opt/company/typedialog/fragments/
├── user-auth.toml
├── database-config.toml
├── api-settings.toml
└── logging.toml

Form reference:

[[item]]
type = "group"
includes = ["user-auth.toml", "database-config.toml"]

Benefit: All projects use same fragments → consistency across organization.

Case 2: Local Overrides

Project needs custom version of standard fragment.

Setup:

export TYPEDIALOG_FRAGMENT_PATH=".typedialog/fragments:/opt/company/typedialog/fragments"

Directory structure:

project/
├── .typedialog/
│   └── fragments/
│       └── user-auth.toml  # ← Custom version
└── form.toml

Form reference:

[[item]]
type = "group"
includes = ["user-auth.toml"]  # Uses local version

Result:

  • user-auth.toml → loads from .typedialog/fragments/ (local override)
  • database-config.toml → loads from /opt/company/... (standard)

Benefit: Override only what you need, rest stays synchronized.

Case 3: Multiple Fragment Sources

Combine fragments from different sources: company library, team library, local.

Setup:

export TYPEDIALOG_FRAGMENT_PATH=".typedialog/fragments:~/team-fragments:/opt/company/fragments"

Search priority:

  1. Project-specific (.typedialog/fragments/)
  2. Team-shared (~/team-fragments/)
  3. Company-wide (/opt/company/fragments/)

Benefit: Flexible hierarchy for different scopes.

Configuration

direnv Integration

Automatically load TYPEDIALOG_FRAGMENT_PATH when entering project directory.

Setup:

# Install direnv
brew install direnv  # macOS
# Or: apt install direnv  # Linux

# Add to shell rc file (~/.bashrc, ~/.zshrc)
eval "$(direnv hook bash)"  # or zsh, fish, etc.

# Create .envrc in project root
cat > .envrc <<EOF
export TYPEDIALOG_FRAGMENT_PATH=".typedialog/fragments:\$HOME/typedialog/fragments"
EOF

# Allow direnv to load .envrc
direnv allow

Result: TYPEDIALOG_FRAGMENT_PATH is automatically set when you cd into project.

Shell Profile

Set globally for all projects.

~/.bashrc or ~/.zshrc:

export TYPEDIALOG_FRAGMENT_PATH="$HOME/.typedialog/fragments:/usr/local/share/typedialog/fragments"

Per-Command

Override for single invocation.

TYPEDIALOG_FRAGMENT_PATH="/custom/path" typedialog form schema.toml

Implementation Details

Code Location

crates/typedialog-core/src/form_parser/parser.rs

Functions:

  • get_fragment_search_paths() - Parse environment variable
  • resolve_fragment_path() - Search directories in order

Logic:

fn resolve_fragment_path(path: &str, base_dir: &Path) -> PathBuf {
    // 1. Absolute path → use directly
    if Path::new(path).is_absolute() {
        return PathBuf::from(path);
    }

    // 2. Try base_dir (backward compatible)
    let base_path = base_dir.join(path);
    if base_path.exists() {
        return base_path;
    }

    // 3. Try each search path
    for search_dir in get_fragment_search_paths() {
        let candidate = search_dir.join(path);
        if candidate.exists() {
            return candidate;
        }
    }

    // 4. Return base_path for error reporting
    base_path
}

Separator Detection

Unix/Linux/macOS: : (colon)

#[cfg(unix)]
let separator = ':';

Windows: ; (semicolon)

#[cfg(windows)]
let separator = ';';

Backward Compatibility

  • If TYPEDIALOG_FRAGMENT_PATH not set → works as before (uses base_dir)
  • Absolute paths → always work regardless of search paths
  • Existing forms → no changes required

Best Practices

DO

  • Use relative paths in form definitions (includes = ["fragment.toml"])
  • Put local overrides first in search path (.typedialog/fragments:/system/fragments)
  • Document custom fragments with comments explaining why local version exists
  • Keep standard structure when overriding (match original fragment structure)
  • Version control .envrc if project-specific paths are important

DON'T

  • Don't hardcode absolute paths in forms (defeats portability)
  • Don't mix path separators (use : on Unix, ; on Windows)
  • Don't create deep hierarchies (2-3 levels max: local, team, system)
  • Don't override without reason (consider if change should be upstream)

Troubleshooting

Fragment not found

Error:

Error: Failed to load fragment 'user-fields.toml': No such file or directory

Check:

# 1. Verify environment variable is set
echo $TYPEDIALOG_FRAGMENT_PATH

# 2. Check if file exists in any search path
ls .typedialog/fragments/user-fields.toml
ls /usr/local/share/typedialog/fragments/user-fields.toml

# 3. Check search order (add debug output)
export TYPEDIALOG_DEBUG=1  # If supported

Wrong version loaded

Symptom: Expected local override, but system version is used.

Check search order:

# Verify local path is FIRST
echo $TYPEDIALOG_FRAGMENT_PATH
# Should be: .typedialog/fragments:...

# Verify local file exists
ls -la .typedialog/fragments/fragment.toml

Windows path issues

Problem: Paths with spaces or special characters.

Solution: Use quotes in environment variable:

set TYPEDIALOG_FRAGMENT_PATH="C:\Program Files\TypeDialog\fragments;D:\Custom Fragments"

Examples

Example 1: Standard Setup

Project structure:

project/
├── form.toml
├── .envrc
└── .typedialog/
    └── fragments/
        └── custom-field.toml

.envrc:

export TYPEDIALOG_FRAGMENT_PATH=".typedialog/fragments:/usr/local/share/typedialog/fragments"

form.toml:

[[item]]
type = "group"
includes = [
    "custom-field.toml",     # Loads from .typedialog/fragments/
    "standard-fields.toml"   # Loads from /usr/local/share/.../
]

Example 2: Multi-Environment

Development:

export TYPEDIALOG_FRAGMENT_PATH=".typedialog/fragments:$HOME/dev-fragments:/opt/fragments"

Production:

export TYPEDIALOG_FRAGMENT_PATH="/opt/company/fragments"

Result: Development has local overrides, production uses only approved fragments.

See Also


Last Updated: 2025-12-26 Feature: TYPEDIALOG_FRAGMENT_PATH Status: Implemented in TypeDialog v0.1.0