Types/OpenPackage.View/at.markpub.markdown.ps1

<#
.SYNOPSIS
    Views input as `at.markpub.markdown`
.DESCRIPTION
    Views any applicable input object as a `at.markpub.markdown` object
.INPUTS
    OpenPackage
.INPUTS
    OpenPackage.Part
.INPUTS
    string
.LINK
    https://markpub.at/
#>

param()

$allInput = @($input) + @($args)

# 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()
        } 
        elseif ($in.Package -is [IO.Packaging.Package]) {
            $in.Package.GetParts()
        }
        elseif ($in) {
            $in
        }
    }
)

# Declare a filter

filter at.markpub.markdown {
    $in = $_
    
    $frontMatter = [Ordered]@{}

    if ($in.Package -and $in.PartUri) {
        $inPart = $in.Package.GetPart($in.PartUri)
        $frontMatter['title'] = $inPart.Name -replace '[\-_]', ' '
        $frontMatter['path'] =
            $in.PartUri -replace '(?>/README|/index)?\.(?>md|markdown)$'

        $inPart = $in.Package.GetPart($in.PartUri)
        $inputMetadata = $inPart.Metadata
        foreach ($metadata in $inputMetadata) {
            if ($metadata -is [Collections.IDictionary]) {
                if ($metadata.PrivateData.PSData -is [Collections.IDictionary]) {
                    $metadata = $metadata.PrivateData.PSData
                }
                foreach ($key in @($metadata.Keys | Sort-Object)) {
                    if (-not $frontMatter.Contains($key)) {
                        $frontMatter[$key] = $metadata[$key]
                    } else {
                        $frontMatter[$key] =
                            @($metadata[$key]) + 
                            $frontMatter[$key]
                    }
                }
            }
            elseif ($metadata -isnot [string] -and 
                $metadata -isnot [xml]) {
                foreach ($property in $metadata.psobject.properties) {
                    if (-not $frontMatter.Contains($property.Name)) {
                        $frontMatter[$property.Name] = $metadata.($property.Name)
                    } else {
                        $frontMatter[$property.Name] = 
                            @($metadata.($property.Name)) +
                            $frontMatter[$property.Name]
                    }
                }
            }
        }
    }

    

    [PSCustomObject]@{
        PSTypeName = 'at.markpub.markdown'
        '$type' = 'at.markpub.markdown'
        'text' = [PSCustomObject]@{
            PSTypeName = 'at.markpub.text'
            '$type' = 'at.markpub.text'
            'markdown' = 
                if ($in -is [string]) {
                    $in
                } elseif ($in.markdown) {
                    $in.markdown
                } else {
                    ''
                }
        }
        'frontMatter' = [PSCustomObject]$frontMatter
    }
}

# Now, let's go over all input
:nextInput foreach ($in in $allInput) {
    # If the input is a string
    if ($in -is [string]) {
        # Just take the markdown,
        # put it in an at.markpub.markdown object,
        # and continue to the next input.
        $in | at.markpub.markdown
        continue nextInput
    }

    if ($in.'$type' -eq 'at.markpub.markdown') {
        $in
        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)$'
    ) {
        # If there is no reader
        if (-not $in.Reader) {
            # write a warning and continue to the next input.
            Write-Warning "No reader for '$($in.Uri)'"
            continue nextInput
        }
        # Read our input and make it `at.markpub.markdown`
        $in.Read() |
            at.markpub.markdown
        # continue to the next input.
        continue nextInput
    }

    if ($in -is [IO.Packaging.PackagePart] -and 
        $in.Uri -match '(?>\.json)$'
    ) {
        # If there is no reader
        if (-not $in.Reader) {
            # write a warning and continue to the next input.
            Write-Warning "No reader for '$($in.Uri)'"
            continue nextInput
        }

        foreach ($value in $in.Read()) {
            if ($value.'$type' -eq 'at.markpub.markdown') {
                $value
            }
            elseif ($value.value.'$type' -eq 'at.markpub.markdown') {
                $value.value
            }
            elseif ($value.record.'$type' -eq 'at.markpub.markdown') {
                $value.record
            }
        }
    }
}