Types/OpenPackage.View/Tree.html.ps1

<#
.SYNOPSIS
    Shows a package tree as HTML
.DESCRIPTION
    Shows a package tree beneath a point as HTML
#>

[OutputType('text/html')]
[PSTypeName('IO.Packaging.Package')]
param(
# Any input
[Parameter(ValueFromPipeline)]
[Alias('Package')]
[PSObject[]]
$InputObject,
    
# The file pattern
[string]
$FilePattern = '.',

# The CSS of the tree
[Alias('CSS')]
[string]
$Style = @"
.directory-name {font-size: 1.5rem;}
.directory { font-size: 1.25rem; }
"@

)


$allInput = @($input)
if ((-not $allInput) -and $InputObject) {
    $allInput += $InputObject
}

filter toIndex {
    $in = $_
    if ($in -is [Collections.IDictionary]) {
        "<ul class='directory'>"
        $in.GetEnumerator() | toIndex
        "</ul>"        
    } elseif ($in.Key -is [string]) {
        
        if ($in.Value -is  [Collections.IDictionary]) {
            "<li><details>"
            "<summary class='directory-name'>$([Web.HttpUtility]::HtmlEncode($in.Key))</summary>"
            $in.Value | toIndex
            "</details></li>"
        } else {
            "<li>"
            "<a href='$([Web.HttpUtility]::HtmlAttributeEncode((
                $in.Value.Uri -replace '\+', '%20'
            )))'>"

            [Web.HttpUtility]::HtmlEncode($in.Key)
            "</a>"
            "</li>"
        }
    }
}

foreach ($in in $allInput) {
    if (-not $in.GetTree) {
        continue
    }

    $fileTree = $in.GetTree($FilePattern)
    @(
        if ($Style) {
            "<style>";$Style;"</style>"
        }
        $fileTree | toIndex
    ) -join [Environment]::NewLine |
        Add-Member NoteProperty Package $in -Force -PassThru |
        Add-Member NoteProperty FilePattern $in -Force -PassThru |
        . {
            process {
                $_.pstypenames.add('text/html')
                $_
            }
        }
}