Alt3.Docusaurus.Powershell.psm1

#Region 'PREFIX' 0
Set-StrictMode -Version Latest
$PSDefaultParameterValues['*:ErrorAction'] = 'Stop' # full stop on first error
#EndRegion 'PREFIX'
#Region '.\Private\getCustomEditUrl.ps1' 0
function GetCustomEditUrl() {
    <#
        .SYNOPSIS
            Returns the `custom_edit_url` for the given .md file.
 
        .DESCRIPTION
            Generates a URL pointing to the Powershell source file that was used to generate the markdown file.
    #>

    param(
        [Parameter(Mandatory = $True)][string]$Module,
        [Parameter(Mandatory = $True)][System.IO.FileSystemInfo]$MarkdownFile,
        [Parameter(Mandatory = $True)][string]$EditUrl,
        [switch]$Monolithic
    )

    # monolithic
    if ($Monolithic) {
        if (Test-Path -Path $Module) {
            $sourceFile = [System.IO.Path]::GetFileNameWithoutExtension($Module) + '.psm1'
        } else {
            $modulePath = (Get-Module $Module).path
            $sourceFile = [System.IO.Path]::GetFileName($modulePath)
        }

        return $EditUrl + '/' + $sourceFile
    }

    # non-monolithic
    $command = [System.IO.Path]::GetFileNameWithoutExtension($MarkdownFile)

    return $EditUrl + '/' + $command + ".ps1"
}
#EndRegion '.\Private\getCustomEditUrl.ps1' 32
#Region '.\Private\getMdxFilePath.ps1' 0
function GetMdxFilePath() {
    <#
        .SYNOPSIS
            Returns the .mdx file path for a given .md file.
    #>

    param(
        [Parameter(Mandatory = $True)][System.IO.FileSystemInfo]$MarkdownFile
    )

    Join-Path $MarkdownFile.DirectoryName -ChildPath "$([System.IO.Path]::GetFileNameWithoutExtension($MarkdownFile.Name)).mdx"
}
#EndRegion '.\Private\getMdxFilePath.ps1' 11
#Region '.\Private\NewSidebarIncludeFile.ps1' 0
function NewSidebarIncludeFile() {
    <#
        .SYNOPSIS
            Generates a `.js` file holding an array with all .mdx 'ids` to be imported in Docusaurus `sidebar.js`.
 
        .LINK
            https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-powershell-1.0/ff730948(v=technet.10)
    #>

    param(
        [Parameter(Mandatory = $True)][string]$OutputFolder,
        [Parameter(Mandatory = $True)][Object]$MarkdownFiles
    )

    # generate a list of Powershell commands by stripping .md from the generated PlatyPs files
    [array]$commands = $MarkdownFiles | Select-Object @{ Name = "PowershellCommand"; Expression={ "'" + [System.IO.Path]::GetFileNameWithoutExtension($_) + "'" } } | Select-Object  -Expand PowershellCommand

    # generate content using Here-String block
$content = @"
/**
 * Import this file in your Docusaurus ``sidebar.js`` file.
 *
 * Auto-generated by Alt3.Powershell.Docusaurus.
 *
 * Copyright (c) 2019-present, ALT3 B.V.
 *
 * Licensed under the MIT license.
 */
 
module.exports = [
    $($commands -Join ",`n ")
];
"@


    # generate file path, convert relative outputfolder to absolute if needed
    if (-Not([System.IO.Path]::IsPathRooted($OutputFolder))) {
        $outputFolder = Join-Path "$(Get-Location)" -ChildPath $OutputFolder
    }

    $filePath = Join-Path -Path $OutputFolder -ChildPath "docusaurus.powershell.sidebar.js"

    # create the file
    $fileEncoding = New-Object System.Text.UTF8Encoding $False
    [System.IO.File]::WriteAllLines($filePath, $content, $fileEncoding)

    # add created file to output
    Get-Item $filePath
}
#EndRegion '.\Private\NewSidebarIncludeFile.ps1' 47
#Region '.\Private\RemoveContentHeaderOne.ps1' 0
function RemoveContentHeaderOne() {
    <#
        .SYNOPSIS
        Removes the H1 element from the markdown content because Docusaurus already generates H1 using the `title` front matter.
    #>

    param(
        [Parameter(Mandatory = $True)][System.IO.FileSystemInfo]$MarkdownFile
    )

    $content = (Get-Content -Path $MarkdownFile.FullName -Raw).TrimEnd()

    #$regex = "(?sm)^(---)(.+)^(---).$\n"
    $regex = '\n#{1}\s.+\n\r'

    $newContent = [regex]::replace($content, $regex, '')

    # replace file (UTF-8 without BOM)
    $fileEncoding = New-Object System.Text.UTF8Encoding $False
    [System.IO.File]::WriteAllLines($markdownFile.FullName, $newContent, $fileEncoding)
}
#EndRegion '.\Private\RemoveContentHeaderOne.ps1' 20
#Region '.\Private\UpdateContentBackticks.ps1' 0
function UpdateContentBackticks() {
    <#
        .SYNOPSIS
        Replaces platyPS-produced "escaped backticks" with normal backticks so markdown gets rendered as expected.
    #>

    param(
        [Parameter(Mandatory = $True)][System.IO.FileSystemInfo]$MarkdownFile
    )

    $content = (Get-Content -Path $MarkdownFile.FullName -Raw).TrimEnd()

    $regex = '\\`'

    $newContent = [regex]::replace($content, $regex, '`')

    # replace file (UTF-8 without BOM)
    $fileEncoding = New-Object System.Text.UTF8Encoding $False
    [System.IO.File]::WriteAllLines($markdownFile.FullName, $newContent, $fileEncoding)
}
#EndRegion '.\Private\UpdateContentBackticks.ps1' 19
#Region '.\Private\UpdateContentCodeBlocks.ps1' 0
function UpdateContentCodeBlocks() {
    <#
        .SYNOPSIS
        Add `powershell` syntax highlighting to generated code blocks.
 
        .NOTES
        1. unfortunately we need to do this because PlatyPS does not add the language (design choice)
        2. @todo change regex so it will match on \n as well (now only works on CRLF files)
    #>

    param(
        [Parameter(Mandatory = $True)][System.IO.FileSystemInfo]$MarkdownFile
    )

    $content = (Get-Content -Path $MarkdownFile.FullName -Raw).TrimEnd()

    # this regex replaces all code blocks without a language (test on https://regex101.com using /$regex/g)
    $regex = '(```)\r((?:(?!```)[\s\S])+)(```)\r'

    $newContent = [regex]::replace($content, $regex, '```powershell$2```')

    # replace file (UTF-8 without BOM)
    $fileEncoding = New-Object System.Text.UTF8Encoding $False
    [System.IO.File]::WriteAllLines($markdownFile.FullName, $newContent, $fileEncoding)
}
#EndRegion '.\Private\UpdateContentCodeBlocks.ps1' 24
#Region '.\Private\UpdateContentFrontMatter.ps1' 0
function UpdateContentFrontMatter() {
    <#
        .SYNOPSIS
            Replaces PlatyPS generated front matter with Docusaurus compatible front matter.
 
        .LINK
            https://www.apharmony.com/software-sagacity/2014/08/multi-line-regular-expression-replace-in-powershell/
    #>

    param(
        [Parameter(Mandatory = $True)][System.IO.FileSystemInfo]$MarkdownFile,
        [Parameter(Mandatory = $True)][string]$CustomEditUrl
    )

    # prepare front matter
    $powershellCommandName = [System.IO.Path]::GetFileNameWithoutExtension($markdownFile.Name)

    $newFrontMatter = @(
        "---"
        "id: $powershellCommandName"
        "title: $powershellCommandName"
        "custom_edit_url: $customEditUrl"
        "---"
    ) | Out-String

    # replace front matter
    $content = (Get-Content -Path $MarkdownFile.FullName -Raw).TrimEnd()

    $regex = "(?sm)^(---)(.+)^(---).$\n"

    $newContent = $content -replace $regex, $newFrontMatter

    # replace file (UTF-8 without BOM)
    $fileEncoding = New-Object System.Text.UTF8Encoding $False
    [System.IO.File]::WriteAllLines($markdownFile.FullName, $newContent, $fileEncoding)
}
#EndRegion '.\Private\UpdateContentFrontMatter.ps1' 35
#Region '.\Public\New-DocusaurusHelp.ps1' 0
function New-DocusaurusHelp() {
    <#
        .SYNOPSIS
            Generates Get-Help documentation in Docusaurus compatible `.mdx` format.
 
        .DESCRIPTION
            The `New-DocusaurusHelp` cmdlet generates Get-Help documentation in Docusaurus
            compatible format by creating an `.mdx` file for each command exported by
            the module, then enriching that file with command specific front matter
            variables.
 
            The cmdlet also creates a `docusaurus.powershell.sidebar.js` file
            containing a list of all documented commands, for easy integration
            into the Docusaurus website sidebar.
 
        .OUTPUTS
            System.Object
 
        .EXAMPLE
            New-DocusaurusHelp -Module Alt3.Docusaurus.Powershell -OutputFolder .\docusaurus\docs\ -EditUrl "https://github.com/alt3/Docusaurus.Powershell/edit/master/source/Public"
 
        .PARAMETER Module
            Specifies the module this cmdlet will generate Docusaurus documentation for.
 
            You may specify a module name, a `.psd1` file or a `.psm1` file.
 
        .PARAMETER OutputFolder
            Specifies the folder where the Docusaurus Get-Help documentation will be created.
 
        .PARAMETER EditUrl
            Specifies the URL prefixed to all Docusaurus `custom_edit_url` front matter variables.
 
        .PARAMETER Monolithic
            Use this optional argument if the Powershell module source is monolithic.
 
            Will point all `custom_edit_url` front matter variables to the `.psm1` file.
 
        .NOTES
            Please note that Docusaurus v2 is an early and alpha version, just like this module.
 
        .LINK
            https://docusaurus.io/
 
        .LINK
            https://github.com/PowerShell/platyPS
    #>

    [cmdletbinding()]
    param(
        [Parameter(Mandatory = $True)][string]$Module,
        [Parameter(Mandatory = $True)][string]$OutputFolder,
        [Parameter(Mandatory = $True)][string]$EditUrl,
        [switch]$Monolithic # pass to edit a single pm file
    )

    # make sure the passed module is valid
    if (Test-Path($Module)) {
        Import-Module $Module -Force -Global
        $Module = [System.IO.Path]::GetFileNameWithoutExtension($Module)
    }

    if (-Not(Get-Module -Name $Module)) {
        $Module = $Module
        throw "New-DocusaurusHelp: Specified module '$Module' is not loaded"
    }

    # generate PlatyPs markdown files
    $markdownFiles = New-MarkdownHelp -Module $Module -OutputFolder $OutputFolder -Force

    # update generated markdown file(s) to make them Docusaurus compatible
    ForEach ($markdownFile in $markdownFiles) {
        $customEditUrl = GetCustomEditUrl -Module $Module -MarkdownFile $markdownFile -EditUrl $EditUrl -Monolithic:$Monolithic

        UpdateContentFrontMatter -MarkdownFile $markdownFile -CustomEditUrl $customEditUrl
        RemoveContentHeaderOne -MarkdownFile $markdownFile
        UpdateContentCodeBlocks -MarkdownFile $markdownFile
        UpdateContentBackticks -MarkdownFile $markdownFile

        # rename to .mdx
        $mdxFilePath = GetMdxFilePath -MarkdownFile $markdownFile
       Move-Item -Path $markdownFile.FullName -Destination $mdxFilePath -Force | Out-Null

        # output .mdx item so end-user can post-process files as they see fit
       Get-Item $mdxFilePath
    }

    # generate the `.js` file used for the docusaurus sidebar
    NewSidebarIncludeFile -MarkdownFiles $markdownFiles -OutputFolder $OutputFolder
}
#EndRegion '.\Public\New-DocusaurusHelp.ps1' 88