Types/OpenPackage.View/Markdown.html.ps1

<#
.SYNOPSIS
    Views Markdown as HTML
.DESCRIPTION
    Views Markdown as HTML
.EXAMPLE

#>

[OutputType('text/html')]
[PSTypeName('string')]
[PSTypeName('IO.Packaging.Package')]
[PSTypeName('IO.Packaging.PackagePart')]
param()

# Quickly enumerate all input and arguments.
$allInput = @($input) + @($args)

# If there is no pipeline builder
if (-not ('Markdig.MarkdownPipelineBuilder' -as [type])) {
    # warn and return
    Write-Warning "Markdig not loaded (ConvertFrom-Markdown is not installed)"
    return
}

# Create the pipeline builder
$mdPipelineBuilder = [Markdig.MarkdownPipelineBuilder]::new()
$mdPipeline = [Markdig.MarkdownExtensions]::UsePipeTables($mdPipelineBuilder).Build()

# Make one quick pass over all input
$allInput = @(
    foreach ($in in $allInput) {
        # and expand any packages we find into their parts.
        if ($in -is [IO.Packaging.Package]) {
            $in.GetParts()
        } else {
            $in
        }
    }
)

# Next make a neat little filter to decorate our output
# We can give PowerShell objects N arbitrary types
# including actual content types
filter text/html {
    # Just check if our typenames do not contain our invocation name
    if ($_.pstypenames -and         
        $_.pstypenames -notcontains $myInvocation.InvocationName) {
        # and add that typename.
        $_.pstypenames.add($myInvocation.InvocationName)
    }
    $_ # and pass thru the input.
}

# Now, let's go over all input
:nextInput foreach ($in in $allInput) {        
    # If the input is a string
    if ($in -is [string]) {
        # Just make the markdown html
        # and stick it in an <article> tag
        "<article>$(
            [Markdig.Markdown]::ToHtml($in, $mdPipeline)
        )</article>"
 | text/html
        # and continue to the next input.
        continue nextInput
    }
    
    # If the input is a package part, we can do more
    if (
        $in -is [IO.Packaging.PackagePart] -and 
        # (if it is not a markdown file, we should ignore it).
        $in.Uri -match '(?>\.md|\.markdown)$'
    ) {
        # Let's read our input real quick:
        $partStream = $in.GetStream('Open', 'Read')        
        $reader = [IO.StreamReader]::new($partStream)
        # Just store the markdown.
        $markdown = $reader.ReadToEnd()
        
        # and clean up.
        $reader.Close(), $reader.Dispose()            
        $partStream.Close(), $partStream.Dispose()

        # We stick the markdown into an article tag
        $markdownHtml = "<article>$(
            $(
                [Markdig.Markdown]::ToHtml($markdown, $mdPipeline)
            )
        )</article>"


        $markdownxhtml = $markdownHtml -as [xml]
        
        foreach ($link in $markdownxhtml | Select-Xml //a) {
            if ($link.Node.href -match '\.(?>md|markdown)$') {
                $link.Node.href = $link.Node.href -replace '^(?<Name>.+?)\.(?>md|markdown)$', 
                    '../${Name}/'
            }
        }

        # And we can use relationships to determine more.
        $part = $in
        
        # If the part had a 'palette' relationship
        $paletteUrl = 
            # If the part had a 'palette' relationship
            if ($part.RelationshipExists('palette')) {
                # use that target uri
                $part.GetRelationship('palette').TargetUri
            } elseif ($part.Package.RelationshipExists('palette')) {
                # alternatively, if the package had a palette, use that.
                $part.Package.GetRelationship('palette').TargetUri
            }
            
        # Now, we can put the markdown into HTML.
        $html = @(
            "<html><head>"
            # The title is easy.
            "<title>"
            $([Web.HttpUtility]::HtmlEncode($part.Name))
            "</title>"
            # If there's a palette url
            if ($paletteUrl) {
                # link the stylesheet with that id.
                "<link rel='stylesheet' id='palette' href='$($paletteUrl)' />"
            }
            "</head>"
            "<body>"
            $markdownxhtml.OuterXml
            "</body>"
            "</html>"
        ) -join [Environment]::NewLine 
        
        $html |
            Add-Member NoteProperty Package $in.Package -Force -PassThru |
            Add-Member NoteProperty PartUri $in.Uri -Force -PassThru |
            Add-Member NoteProperty Part $in -Force -PassThru |
            text/html
        
        # continue to the next input.
        continue nextInput
    }
}