functions/Read-EBCssStyleSheet.ps1

function Read-EBCssStyleSheet
{
<#
    .SYNOPSIS
        Parse a stylesheet and convert it into an object model.
     
    .DESCRIPTION
        Parse a stylesheet and convert it into an object model.
     
    .PARAMETER CssData
        CSS data provided as a string.
     
    .PARAMETER Path
        Path to CSS stylesheets to parse.
     
    .PARAMETER Merge
        For all styles bound to a class, merge in the settings of the base styles for the tag the class applies to.
     
    .EXAMPLE
        PS C:\> Read-EBCssStyleSheet -CssData $content
     
        Parses the CSS styles contained as string in $content
     
    .EXAMPLE
        PS C:\> Get-ChildItem *.css | Read-EBCssStyleSheet
     
        Parses all CSS stylesheets in the current folder.
#>

    [OutputType([EbookBuilder.StyleObject])]
    [CmdletBinding(DefaultParameterSetName = 'Text')]
    param (
        [Parameter(Mandatory = $true, Position = 0, ParameterSetName = 'Text')]
        [string]
        $CssData,
        
        [Parameter(Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'File')]
        [Alias('FullName')]
        [string[]]
        $Path,
        
        [switch]
        $Merge
    )
    
    begin{
        #region Functions
        function Convert-StyleSheet {
            [CmdletBinding()]
            param (
                [Parameter(ValueFromPipeline = $true)]
                [string[]]
                $Text,
                
                [hashtable]
                $ResultHash
            )
            
            begin {
                $currentTag = ''
                $currentClass = '_default'
                $inComment = $false
            }
            process {
                foreach ($line in $Text | Get-SubString -Trim " " | Split-String "`n" | Get-SubString -Trim " " | Remove-PSFNull) {
                    Write-PSFMessage -Level InternalComment -Message ' {0}' -StringValues $line
                    #region Comments
                    if ($line -match "^/\*") { $inComment = $true }
                    if ($line -match "\*/") { $inComment = $false }
                    if ($inComment -or $line -match "^/\*" -or $line -match "\*/") { continue }
                    #endregion Comments
                    
                    #region Close CSS
                    if ($line -eq "}") {
                        $currentTag = ''
                        $currentClass = '_default'
                        
                        continue
                    }
                    #endregion Close CSS
                    
                    #region Open CSS
                    if ($line -like "*{") {
                        $tempLine = $line | Get-SubString -TrimEnd " {"
                        $segments = $tempLine -split "\.",2
                        $currentTag = $segments[0]
                        if ($segments[1]) { $currentClass = $segments[1] }
                        else { $currentClass = '_default' }
                        continue
                    }
                    #endregion Open CSS
                    
                    #region Content
                    if (-not $ResultHash[$currentTag]) { $ResultHash[$currentTag] = @{ } }
                    if (-not $ResultHash[$currentTag][$currentClass]) { $ResultHash[$currentTag][$currentClass] = @{ } }
                    
                    $key, $value = $line -split ":", 2
                    Write-PSFMessage -Level InternalComment -Message ' {0} : {1}' -StringValues $key, $value
                    $ResultHash[$currentTag][$currentClass][$key.Trim()] = $value.Trim(" ;")
                    #endregion Content
                }
            }
        }
        
        function Resolve-StyleHash {
            [OutputType([EbookBuilder.StyleObject])]
            [CmdletBinding()]
            param (
                [hashtable]
                $ResultHash,
                
                [bool]
                $Merge
            )
            
            foreach ($pair in $ResultHash.GetEnumerator()) {
                $tagName = $pair.Key
                
                $defaultStyle = @{ }
                if ($Merge -and $pair.Value._Default) {
                    $defaultStyle = $pair.Value._Default
                }
                
                foreach ($entry in $pair.Value.GetEnumerator()) {
                    $style = [EbookBuilder.StyleObject]::new()
                    $style.Tag = $tagName
                    if ($entry.Key -ne '_default') { $style.Class = $entry.Key }
                    
                    $hash = $defaultStyle.Clone()
                    foreach ($attribute in $entry.Value.GetEnumerator()) { $hash[$attribute.Key] = $attribute.Value }
                    foreach ($attribute in $hash.GetEnumerator()) { $style.Attributes[$attribute.Key] = $attribute.Value }
                    $style
                }
            }
        }
        #endregion Functions
        
        $resultHash = @{ }
    }
    process
    {
        if ($CssData) { $CssData | Convert-StyleSheet -ResultHash $resultHash }
        foreach ($filePath in $Path) {
            Write-PSFMessage -Message 'Loading style file: {0}' -StringValues $filePath
            Get-Content -Path $filePath | Convert-StyleSheet -ResultHash $resultHash
        }
    }
    end
    {
        Resolve-StyleHash -ResultHash $resultHash -Merge $Merge
    }
}