Transpilers/Templates/Markdown.Template.psx.ps1

<#
.SYNOPSIS
    Markdown Template Transpiler.
.DESCRIPTION
    Allows PipeScript to generate Markdown.

    Because Markdown does not support comment blocks, PipeScript can be written inline inside of specialized Markdown code blocks.

    PipeScript can be included in a Markdown code block that has the Language ```PipeScript{```
    
    In Markdown, PipeScript can also be specified as the language using any two of the following characters ```.<>```
.Example
    .> {
        $markdownContent = @'
# Thinking of a Number Between 1 and 100: ```.<{Get-Random -Min 1 -Max 100}>.``` is the number

### abc

~~~PipeScript{
    '* ' + @("a", "b", "c" -join ([Environment]::Newline + '* '))
}
~~~

#### Guess what, other code blocks are unaffected
~~~PowerShell
1 + 1 -eq 2
~~~


'@
        [OutputFile('.\HelloWorld.ps1.md')]$markdownContent
    }

    .> .\HelloWorld.ps1.md
#>

[ValidatePattern('\.(?>md|markdown|txt)$')]
param(
# The command information. This will include the path to the file.
[Parameter(Mandatory,ValueFromPipeline,ParameterSetName='TemplateFile')]
[Management.Automation.CommandInfo]
$CommandInfo,

# If set, will return the information required to dynamically apply this template to any text.
[Parameter(Mandatory,ParameterSetName='TemplateObject')]
[switch]
$AsTemplateObject,

# A dictionary of parameters.
[Collections.IDictionary]
$Parameter,

# A list of arguments.
[PSObject[]]
$ArgumentList
)

begin {
    # We start off by declaring a number of regular expressions:
    
    $startComment = '(?>
        # Match three ticks or tildas
        (?>```|~~~|) |
        # Or three ticks or tilda, as long as they were preceeded by a newline and followed by less than three spaces.
        (?<=(?>[\r\n]+){1})
        [\s-[\r\n]]{0,3}
        (?>```|~~~)
    ){1}(?>
        # Then, match two characters in the set .<>
        [\.\<\>]{2}
        |
        PipeScript # or match the literal word PipeScript
    )\s{0,}
    # followed by a bracket and any opening whitespace.
    \{\s{0,}
'
 
    $endComment   = '\}(?>[\.\<\>]{2}|PipeScript){0,1}(?>
        \s{0,}(?>[\r\n]+){1}\s{0,3}(?>```|~~~)
        |
        (?>```|~~~)
    )
    '

    
    $startRegex = "(?<PSStart>${startComment})"
    # * EndRegex ```$whitespace + '}' + $EndComment```
    $endRegex   = "(?<PSEnd>${endComment})"

    # Create a splat containing arguments to the core inline transpiler
    $Splat      = [Ordered]@{
        StartPattern  = $startRegex
        EndPattern    = $endRegex
    }
}

process {
    # If we have been passed a command
    if ($CommandInfo) {
        # add parameters related to the file.
        $Splat.SourceFile = $commandInfo.Source -as [IO.FileInfo]
        $Splat.SourceText = [IO.File]::ReadAllText($commandInfo.Source)
    }
    
    if ($Parameter) { $splat.Parameter = $Parameter }
    if ($ArgumentList) { $splat.ArgumentList = $ArgumentList }
    $Splat.ForeachObject = {
        process {
            if ($_ -is [string]) {
                $_
            } elseif ($_.GetType -and $_.GetType().IsPrimitive) {
                $_
            } else {
                $markdownObject = [PSObject]::new($_)
                $markdownObject.pstypenames.clear()
                $markdownObject.pstypenames.add('Markdown')
                $markdownObject | Out-String -Width 1kb
            }
        }
    }
    # If we are being used within a keyword,
    if ($AsTemplateObject) {
        $splat # output the parameters we would use to evaluate this file.
    } else {
        # Otherwise, call the core template transpiler
        .>PipeScript.Template @Splat # and output the changed file.
    }
}