1+ <#
2+ . SYNOPSIS
3+ Yaml File Transpiler.
4+ . DESCRIPTION
5+ Transpiles Yaml with Inline PipeScript into Yaml.
6+
7+ Because Yaml does not support comment blocks, PipeScript can be written inline inside of specialized Yaml string.
8+
9+ PipeScript can be included in a multiline Yaml string with the Key PipeScript and a Value surrounded by {}
10+ . Example
11+ .> {
12+ $yamlContent = @'
13+ PipeScript: |
14+ {
15+ @{a='b'}
16+ }
17+
18+ List:
19+ - PipeScript: |
20+ {
21+ @{a='b';k2='v';k3=@{k='v'}}
22+ }
23+ - PipeScript: |
24+ {
25+ @(@{a='b'}, @{c='d'})
26+ }
27+ - PipeScript: |
28+ {
29+ @{a='b'}, @{c='d'}
30+ }
31+ '@
32+ [OutputFile('.\HelloWorld.ps1.yaml')]$yamlContent
33+ }
34+
35+ .> .\HelloWorld.ps1.yaml
36+ #>
37+ [ValidateScript ({
38+ $cmdInfo = $_
39+ if ($cmdInfo.Source -match ' \.(?>yml|yaml)$' ) {
40+ return $true
41+ }
42+ return $false
43+ })]
44+ param (
45+ # The command information. This will include the path to the file.
46+ [Parameter (Mandatory , ValueFromPipeline )]
47+ $CommandInfo ,
48+
49+ # A dictionary of parameters.
50+ [Collections.IDictionary ]
51+ $Parameter ,
52+
53+ # A list of arguments.
54+ [PSObject []]
55+ $ArgumentList
56+ )
57+
58+ begin {
59+ # We start off by declaring a number of regular expressions:
60+
61+ # Create a splat containing arguments to the core inline transpiler
62+ $Splat = [Ordered ]@ {
63+ ReplacePattern = [Regex ]::new('
64+ (?<Indent>\s{0,}) # Capture the indentation level
65+ (?<InList>-\s)? # Determine if we are in a list
66+ PipeScript # Then match the key Pipescript
67+ :\s\| # followed by a whitespace and pipe character
68+ (?>\r\n|\n){1,} # Match one or more newlines
69+ (\k<Indent>)\s{2} # The ScriptBlock must be indented at least two spaces
70+ (?(InList)\s{2}) # (four if it is a list)
71+ \{ # Then we need to match the opening brace
72+ (?<PipeScript> # And we finally start matching our Script
73+ (?:.|\s){0,}?(?= # This is zero or more characters until
74+ \z| # The end of the string OR
75+ (\k<Indent>)\s{2} # A Matching pair or quad of indentation.
76+ (?(InList)\s{2})
77+ \} # followed by a closing brace.
78+ )
79+ )
80+ (\k<Indent>)\s{2} # To complete the match, we check indentation once more
81+ (?(InList)\s{2})
82+ \}
83+ ' , ' IgnorePatternWhitespace,IgnoreCase' )
84+ }
85+ }
86+
87+ process {
88+ # Add parameters related to the file
89+ $Splat.SourceFile = $commandInfo.Source -as [IO.FileInfo ]
90+ $Splat.SourceText = [IO.File ]::ReadAllText($commandInfo.Source )
91+ if ($Parameter ) { $splat.Parameter = $Parameter }
92+ if ($ArgumentList ) { $splat.ArgumentList = $ArgumentList }
93+ $Splat.ForeachObject = {
94+ begin {
95+ $yamlOut = [Collections.Queue ]::new()
96+ }
97+ process {
98+ $YamlOut.Enqueue ($_ )
99+ }
100+ end {
101+ if ($yamlOut.Count -eq 1 ) {
102+ $yamlOut = $yamlOut [0 ]
103+ } else {
104+ $isList = $true
105+ }
106+
107+ @ (foreach ($yo in $yamlOut ) {
108+ if ($yo -is [string ]) {
109+
110+ }
111+ if ($yo -is [Collections.IDictionary ]) {
112+ $yo = [PSCustomObject ]$yo
113+ }
114+ $yamlObject = [PSCustomObject ]::new($yo )
115+ $yamlObject.pstypenames.clear ()
116+ $yamlObject.pstypenames.add (' Yaml' )
117+ $yamlLines = @ ((Out-String - InputObject $yamlObject - Width 1 kb ).Trim() -split ' (?>\r\n|\n)' )
118+ $isList = $yamlLines [0 ] -match ' ^-\s'
119+ $inList = $match.Groups [" InList" ].Value -as [bool ]
120+ $yamlIndent = ' ' * ($match.Groups [" Indent" ].Length -as [int ])
121+ @ (for ($yamlLineNumber = 0 ; $yamlLineNumber -lt $yamlLines.Length ; $yamlLineNumber ++ ) {
122+ $yamlLine = $yamlLines [$yamlLineNumber ]
123+ $ (if ($inList -and -not $isList ) {
124+ if (-not $yamlLineNumber ) {
125+ $yamlIndent + ' - '
126+ } else {
127+ $yamlIndent + ' '
128+ }
129+ } else {
130+ $yamlIndent
131+ }) + $yamlLine
132+ }) -join [Environment ]::NewLine
133+ }) -join [Environment ]::Newline
134+ }
135+ }
136+ # Call the core inline transpiler.
137+ .> PipeScript.Inline @Splat
138+ }
0 commit comments