MetaNullWiki.psm1

#Requires -Module ConfluencePS
#Requires -Module MetaNullUtils
# Module Constants

Set-Variable CWikiNamespaces -option Constant -value @('ac','ri')
Function Clear-Placeholder {
<#
    .Synopsis
        Remove any Wiki placeholders (template values, that are not displayed in view mode) from a piece of html
    .PARAMETER InputHtml
        The HTML input
    .EXAMPLE
        $Body | Select-Placeholder
#>

[CmdletBinding(SupportsShouldProcess=$false)]
[OutputType([string])]
param (
    [Parameter(Position=0, ValueFromPipeline)]
    [AllowEmptyString()]
    [Alias('Html','String')]
    [string]$InputHtml
)
Process {
    $InputHtml -replace '<(ac:placeholder\b).*?>.*?</\1>' | Write-Output
}
}
Function ConvertFrom-Artifact {
<#
    .SYNOPSIS
        Convert a WikiArtifact object into the best matching type of artifact
    .Description
        Convert a WikiArtifact object into the best matching type of artifact. The function checks the presence of specific Page Properties OR specific Labels
    .PARAMETER InputArtifact
        The input object.
#>

[CmdletBinding()]
[OutputType(
    [WikiArtifact],
    [WikiDomain],
    [WikiProduct],
    [WikiContainer],
    [WikiTechnology],
    [WikiKeyDataEntity]
    )
]
param (
    [Parameter(ValueFromPipeline, Position=0)]
    [AllowEmptyString()]
    [Alias('Artifact','Product','Container','Technology','KeyDataEntity','Object')]
    [WikiArtifact]$InputArtifact
)
Process {
    if($InputArtifact.Properties.Id -contains 'info' -or $InputArtifact.Labels -contains 'product') {
        [WikiProduct]::new($InputArtifact) | Write-Output
    } elseif($InputArtifact.Properties.Id -contains 'container' -or $InputArtifact.Labels -contains 'container') {
        [WikiContainer]::new($InputArtifact) | Write-Output
    } elseif($InputArtifact.Properties.Id -contains 'technology' -or $InputArtifact.Labels -contains 'technology') {
        [WikiTechnology]::new($InputArtifact) | Write-Output
    } elseif($InputArtifact.Properties.Id -contains 'domain' -or $InputArtifact.Labels -contains 'domain') {
        [WikiDomain]::new($InputArtifact) | Write-Output
    } elseif($InputArtifact.Properties.Id -contains [string]::Empty -or $InputArtifact.Labels -contains 'key-data-entity') {
        [WikiKeyDataEntity]::new($InputArtifact) | Write-Output
    } elseif($InputArtifact.Properties.Length -gt 0) {
        $InputArtifact | Write-Output
    } else {
        # Nothing to return, Input Object was probably not a valid artifact
    }
}
}
Function ConvertTo-XDocument {
<#
    .SYNOPSIS
        Convert a piece of html into a XDocument
    .Description
        Convert a piece of (well formed) html into a XDocument
    .PARAMETER InputString
        The input string. It must contain a valid piece of XHTML
#>

[CmdletBinding()]
[OutputType([System.Xml.Linq.XDocument])]
param (
    [Parameter(ValueFromPipeline, Position=0)]
    [AllowEmptyString()]
    [Alias('String','Html')]
    [String]$InputString
)
Process {
    &([MetaNullWiki]::Utils('ConvertTo-XDocument')) -InputString $InputString -Namespaces $CWikiNamespaces | Write-Output
}
}
Function Select-HyperLink {
<#
    .Synopsis
        Select the title and uri of html hyperlinks
    .PARAMETER InputHtml
        The HTML input
    .EXAMPLE
        # Get all hyperlinks in a html page
        $Body | Select-Hyperlink
#>

[CmdletBinding()]
[OutputType([string[]])]
param (
    [Parameter(Position=0, ValueFromPipeline)]
    [AllowEmptyString()]
    [Alias('Html','String')]
    [string]$InputHtml
)
Process {
    $InputHtml | ConvertTo-XDocument | Select-Xpath -XPath '//a[@href]' | Foreach-Object {
        $Href = $_ | Select-XPath -XPath './@href' | Select-Object -ExpandProperty Node | Select-Object -ExpandProperty Value
        $Node = $_ | Select-XPath -XPath '.' | Select-Object -ExpandProperty Node
        $Body = $Node | Select-Object -ExpandProperty InnerXml
        $Text = $Node | Select-Object -ExpandProperty InnerText
        [PSCustomObject]@{
            Href = $Href
            Text = $Text
            Body = $Body
        } | Write-Output
    }
}
}
Function Select-LinkCard {
<#
    .Synopsis
        Select the "titles" of all wiki link cards in a blob of (html) text
    .PARAMETER InputHtml
        The HTML input
    .EXAMPLE
        # Get the titles from all link cards
        $Body | Select-LinkCard
#>

[CmdletBinding()]
[OutputType([string[]])]
param (
    [Parameter(Position=0, ValueFromPipeline)]
    [AllowEmptyString()]
    [Alias('Html','String')]
    [string]$InputHtml
)
Begin {
    $xpathSelectors = @(
        "//ac:link/ri:page/@ri:content-title"
    )
    $xpathExpression = "($($xpathSelectors -join ' | '))"
}
Process {
    $InputHtml | ConvertTo-XDocument | Select-Xpath -XPath $xpathExpression | Select-Object -ExpandProperty Node | Select-Object -ExpandProperty Value | Write-Output
}
}
Function Select-Macro {
<#
    .Synopsis
        Select the content of all excerpt macros in a wiki page (html)
 
    .EXAMPLE
        # Get the body from all exerpt macros
        $Body | Select-Excerpt
#>

[CmdletBinding()]
[OutputType([MetaNullWiki.Macro[]])]
param (
    [Parameter(Position=0, ValueFromPipeline)]
    [AllowEmptyString()]
    [Alias('Html','String')]
    [string]$InputHtml
)
Process {
    $Macros = $InputHtml | ConvertTo-XDocument | Select-Xpath -XPath '//ac:structured-macro'
    $Macros | ForEach-Object {
        $Object = [MetaNullWiki.Macro]::new()

        $Macro = $_
        $Object.Name = $Macro | Select-Xpath -XPath '@ac:name[position()=1]' | Select-Object -ExpandProperty Node | Select-Object -ExpandProperty Value
        $Object.Parameters = @{}
        $Macro | Select-Xpath -XPath 'ac:parameter' | Select-Object -ExpandProperty Node | Select-Object name,InnerText | Foreach-Object {
            $Object.Parameters.($_.name) = $_.InnerText
        }
        $Object.Body = $Macro | Select-Xpath -XPath 'ac:rich-text-body' | Select-Object -ExpandProperty Node | Select-Object -ExpandProperty InnerXml
        $Object.Attributes = @{}
        $Macro | Select-Xpath -XPath '@*' | Select-Object -ExpandProperty Node | Select-Object Name,Value | Foreach-Object {
            $Object.Attributes.($_.Name) = $_.Value
        }
        $Object | Write-Output
    }
}
}
Function Select-Placeholder {
<#
    .Synopsis
        Select the content of all Wiki placeholders (template values, that are not displayed in view mode)
    .PARAMETER InputHtml
        The HTML input
    .EXAMPLE
        $Body | Select-Placeholder
#>

[CmdletBinding()]
[OutputType([string[]])]
param (
    [Parameter(Position=0, ValueFromPipeline)]
    [AllowEmptyString()]
    [Alias('Html','String')]
    [string]$InputHtml
)
Begin {
    $xpathExpression = "//ac:placeholder"
}
Process {
    $InputHtml | ConvertTo-XDocument | Select-Xpath -XPath $xpathExpression | Select-Object -ExpandProperty Node | Select-Object -ExpandProperty InnerXml | Write-Output
}
}
Function Select-Text {
<#
    .Synopsis
        Select the content of all text nodes in a blob of (html) text
    .PARAMETER InputHtml
        The HTML input
    .EXAMPLE
        # Extract the piexes of text from (x|ht)ml
        '<strong>Meta<u>Null</u></strong><p>was here</p>' | Select-Text
#>

[CmdletBinding()]
[OutputType([string[]])]
param (
    [Parameter(Position=0, ValueFromPipeline)]
    [AllowEmptyString()]
    [Alias('Html','String')]
    [string]$InputHtml
)
Begin {
    $xpathSelectors = @(
        "/xml//*[local-name()=name()]"
        "//ac:link/ac:link-body"
        "//ac:structured-macro[@ac:name='status']/ac:parameter[@ac:name='title']"
    )
    $xpathExpression = "($($xpathSelectors -join ' | '))/text()[normalize-space()]"
}
Process {
    if($InputHtml -notmatch '[<>]') {
        $InputHtml | Write-Output
    } else {
        $InputHtml | ConvertTo-XDocument | Select-Xpath -XPath $xpathExpression | Select-Object -ExpandProperty Node | Select-Object -ExpandProperty InnerText | Write-Output
    }
    
}
}
Function Select-VersionLinkCard {
<#
    .Synopsis
        Select "Versions", representred by a wiki link card and a free text version number in (html) text
    .PARAMETER InputHtml
        The HTML input
    .EXAMPLE
        # Get the titles from all link cards
        $Body | Select-VersionLinkCard
#>

[CmdletBinding()]
[OutputType([WikiVersionLink[]])]
param (
    [Parameter(Mandatory, Position=0, ValueFromPipeline)]
    [AllowEmptyString()]
    [Alias('Html','String')]
    [string]$InputHtml
)
Process {
    [WikiVersionLink]::CreateFromHtml($InputHtml)
}
}
Function Select-Xpath {
<#
    .SYNOPSIS
        Use XPath on a blob of (xhtml) text
    .Description
        Use XPath on a blob of (xhtml) text.
    .PARAMETER InputDocument
        The input XML onwhich to run xpath
    .PARAMETER Xpath
        The xpath query string
    .PARAMETER Namespaces
        A list of additional NS to declare
    .EXAMPLE
        # Get URL from all hyperlinks in a page
        $Html | ConvertTo-XDocument | Select-Xpath -XPath '//a/@href/text()'
#>

[CmdletBinding(DefaultParameterSetName)]
[OutputType([object[]])]
param (
    [Parameter(Mandatory, Position=0)]
    [string]$XPath,

    [Parameter(ValueFromPipeline,Mandatory,Position=1)]
    [Alias('Document','Xml','Node')]
    [object]$InputDocument
)
Process {
    $InputDocument | &([MetaNullWiki]::Utils('Select-XPath')) -Namespaces $CWikiNamespaces -XPath $Xpath | Write-Output
}
}