soft-canonicalize 0.5.6

Path canonicalization that works with non-existing paths.
Documentation
name: CI
# 
# This workflow runs CI checks on GitHub Actions.
# For local development with auto-fixing, use: bash ci-local.sh

on:
  push:
    branches: [ dev ]

env:
  CARGO_TERM_COLOR: always

jobs:
  test:
    name: Test
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        os: [ubuntu-latest, windows-latest, macos-latest]

    steps:
    - uses: actions/checkout@v4
    
    - name: Validate file encodings
      shell: bash
      run: |
        echo "๐Ÿ” Validating UTF-8 encoding for critical files..."
        
        # Function to check UTF-8 encoding cross-platform
        check_utf8() {
          local file="$1"
          
          # Check if file exists
          if [ ! -f "$file" ]; then
            echo "โŒ File not found: $file"
            return 1
          fi
          
          # On Linux/macOS, use file command
          if command -v file >/dev/null 2>&1; then
            local file_output=$(file "$file")
            # Check for UTF-8, ASCII, text files, or source files (which are typically UTF-8)
            if echo "$file_output" | grep -q "UTF-8\|ASCII\|text\|[Ss]ource"; then
              echo "โœ… $file: UTF-8 encoding verified (file command)"
            else
              echo "โŒ $file is not UTF-8 encoded"
              echo "   File command output: $file_output"
              return 1
            fi
          else
            # On Windows or if file command not available, check for common non-UTF-8 patterns
            # Check for UTF-16 BOM (FF FE or FE FF)
            if head -c 2 "$file" | xxd | grep -q "fffe\|feff"; then
              echo "โŒ $file appears to be UTF-16 encoded (found BOM)"
              return 1
            fi
            
            # Try to validate UTF-8 by reading with Python (usually available)
            if command -v python3 >/dev/null 2>&1; then
              python3 -c "
        import sys
        try:
            with open('$file', 'r', encoding='utf-8') as f:
                f.read()
            print('โœ… $file: UTF-8 encoding verified (Python check)')
        except UnicodeDecodeError:
            print('โŒ $file: Not valid UTF-8')
            sys.exit(1)
              " || return 1
            else
              echo "โš ๏ธ  Cannot verify encoding for $file (no validation tools available)"
            fi
          fi
        }
        
        # Check README.md
        check_utf8 "README.md"
        
        # Check for UTF-8 BOM in README.md (should not be present)
        if command -v xxd >/dev/null 2>&1; then
          if head -c 3 README.md | xxd | grep -q "efbbbf"; then
            echo "โŒ README.md contains UTF-8 BOM (should be UTF-8 without BOM)"
            exit 1
          fi
          echo "โœ… README.md: No BOM detected (correct)"
        elif command -v od >/dev/null 2>&1; then
          if head -c 3 README.md | od -t x1 | grep -q "ef bb bf"; then
            echo "โŒ README.md contains UTF-8 BOM (should be UTF-8 without BOM)"
            exit 1
          fi
          echo "โœ… README.md: No BOM detected (correct)"
        fi
        
        # Check Cargo.toml
        check_utf8 "Cargo.toml"
        
        # Check all Rust source files
        find src -name "*.rs" | while read file; do
          check_utf8 "$file"
        done
        echo "โœ… All Rust source files: UTF-8 encoding verified"
        
        echo "๐ŸŽ‰ All file encoding checks passed!"
    
    - name: Install Rust
      uses: dtolnay/rust-toolchain@stable
      with:
        components: rustfmt, clippy

    - name: Cache cargo registry
      uses: actions/cache@v4
      with:
        path: |
          ~/.cargo/registry/index/
          ~/.cargo/registry/cache/
          ~/.cargo/git/db/
        key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
        restore-keys: |
          ${{ runner.os }}-cargo-

    - name: Cache cargo build
      uses: actions/cache@v4
      with:
        path: target/
        key: ${{ runner.os }}-cargo-build-${{ hashFiles('**/Cargo.lock') }}
        restore-keys: |
          ${{ runner.os }}-cargo-build-

    - name: Check formatting
      run: cargo fmt --all -- --check

    - name: Show formatting diff (if check failed)
      if: failure()
      run: |
        echo "โŒ Formatting check failed. Run 'cargo fmt --all' to fix."
        echo "Here's what would be changed:"
        cargo fmt --all -- --check --verbose || true
        echo ""
        echo "To fix locally, run: cargo fmt --all"

    - name: Run clippy
      run: cargo clippy --all-targets --all-features -- -D warnings

    - name: Show clippy fixes (if check failed)  
      if: failure()
      run: |
        echo "โŒ Clippy check failed. Some issues might be auto-fixable."
        echo "To fix locally, run: cargo clippy --fix --allow-dirty --allow-staged --all-targets --all-features"
        echo "Then run: cargo clippy --all-targets --all-features -- -D warnings"

    - name: Run tests
      run: cargo test --verbose

    - name: Test feature combinations
      shell: bash
      run: |
        echo "๐Ÿงช Testing feature combinations explicitly..."
        echo ""
        echo "1๏ธโƒฃ  Testing: anchored only"
        cargo test --features anchored --verbose
        echo ""
        
        # dunce feature is Windows-only, skip on Unix/Linux/macOS
        if [ "${{ runner.os }}" == "Windows" ]; then
          echo "2๏ธโƒฃ  Testing: anchored + dunce (Windows-only)"
          cargo test --features anchored,dunce --verbose
          echo ""
          echo "โœ… Both feature combinations passed!"
        else
          echo "โ„น๏ธ  Skipping dunce feature tests (Windows-only, current OS: ${{ runner.os }})"
          echo "โœ… anchored feature tests passed!"
        fi

  docs:
    name: Documentation
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    
    - name: Install Rust
      uses: dtolnay/rust-toolchain@stable
    
    - name: Check documentation
      run: cargo doc --no-deps --document-private-items --all-features
      env:
        RUSTDOCFLAGS: -D warnings

  msrv:
    name: Minimum Supported Rust Version
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    
    - name: Install Rust 1.70
      uses: dtolnay/rust-toolchain@master
      with:
        toolchain: 1.70.0
        components: clippy
    
    - name: Check with MSRV
      run: cargo check --verbose
    
    - name: Run clippy with MSRV
      run: cargo clippy --all-targets --all-features -- -D warnings