Languages/CSS/CSS-Language.ps1
function Language.CSS { <# .SYNOPSIS CSS Language Definition. .DESCRIPTION Allows PipeScript to generate CSS. Multiline comments with /*{}*/ will be treated as blocks of PipeScript. Multiline comments can be preceeded or followed by 'empty' syntax, which will be ignored. The CSS Inline Transpiler will consider the following syntax to be empty: * ```(?<q>["'])\#[a-f0-9]{3}(\k<q>)``` * ```\#[a-f0-9]{6}``` * ```[\d\.](?>pt|px|em)``` * ```auto``` .EXAMPLE .> { $StyleSheet = ' MyClass { text-color: "#000000" /*{ "''red''", "''green''","''blue''" | Get-Random }*/; } ' [Save(".\StyleSheet.ps1.css")]$StyleSheet } .> .\StyleSheet.ps1.css #> [ValidatePattern('\.s{0,1}css$')] param() $this = $myInvocation.MyCommand if (-not $this.Self) { $languageDefinition = New-Module { param( ) $FilePattern = '\.s{0,1}css$' # We start off by declaring a number of regular expressions: $startComment = '/\*' # * Start Comments ```\*``` $endComment = '\*/' # * End Comments ```/*``` $Whitespace = '[\s\n\r]{0,}' $ignoreEach = '[''"]{0,1}\#[a-f0-9]{6}[''"]{0,1}', '[''"]{0,1}\#[a-f0-9]{3}[''"]{0,1}', '[\d\.]+(?>em|pt|px){0,1}', 'auto', "''" $IgnoredContext = "(?<ignore>(?>$($ignoreEach -join '|'))\s{0,}){0,1}" # * StartRegex ```$IgnoredContext + $StartComment + '{' + $Whitespace``` $StartPattern = "(?<PSStart>${IgnoredContext}${startComment}\{$Whitespace)" # * EndRegex ```$whitespace + '}' + $EndComment + $ignoredContext``` $EndPattern = "(?<PSEnd>$Whitespace\}${endComment}\s{0,}${IgnoredContext})" $begin = { filter OutputCSS { $in = $_ # Capture the input object into a variable. if ($in -is [string]) { # If the input was a string return $in # directly embed it. } elseif ($in -is [object[]]) { # If the input was an array # pipe back to ourself (increasing the depth) @($in | & $MyInvocation.MyCommand.ScriptBlock -CssDepth $CssDepth) -join [Environment]::NewLine } else { # Otherwise # we want to treat everything as a dictionary $inDictionary = [Ordered]@{} # so take any object that isn't a dictionary if ($in -isnot [Collections.IDictionary]) { # and make it one. foreach ($prop in $in.PSObject.properties) { $inDictionary[$prop.Name] = $prop.Value } } else { $inDictionary += $in } # Then walk over each key/valye in the dictionary $innerCss = $(@(foreach ($kv in $inDictionary.GetEnumerator()) { if (-not $kv.Value.GetType()) { continue } $cssRuleValueType = $kv.Value.GetType() if ($cssRuleValueType -notin [string],[double],[int]) { $innerDepth = $CssDepth + 1 $kv.Key + ' ' + "{$([Environment]::Newline + (' ' * 2 * $innerDepth))$(@($kv.Value | & $MyInvocation.MyCommand.ScriptBlock -CssDepth $innerDepth) -replace '^\s{0,}' -replace '\s{0,}$' -join ( '; ' ) )$([Environment]::NewLine)}" } else { $kv.Key + ':' + $(if ($kv.Value -eq '') {"''"} else { $kv.Value }) } }) -join ( ';' + [Environment]::NewLine + (' ' * 2 * ($cssDepth)) )) $(if ($cssDepth){'{'} else {''}) + [Environment]::NewLine + (' ' * 2 * ($cssDepth)) + $innerCss + [Environment]::NewLine + (' ' * 2 * ([Math]::max($cssDepth - 1,1))) + $(if ($cssDepth){'}'} else {''}) } } } $ForeachObject = { $_ | OutputCSS } $LanguageName = 'CSS' Export-ModuleMember -Variable * -Function * -Alias * } -AsCustomObject $languageDefinition.pstypenames.clear() $languageDefinition.pstypenames.add("Language") $languageDefinition.pstypenames.add("Language.CSS") $this.psobject.properties.add([PSNoteProperty]::new('Self',$languageDefinition)) } $this.Self } |