Skip to content

Commit 46e4fb3

Browse files
author
James Brundage
committed
Adding support for Pipescript inline in YAML (#147)
1 parent 97d7d40 commit 46e4fb3

File tree

1 file changed

+138
-0
lines changed

1 file changed

+138
-0
lines changed
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
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 1kb).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

Comments
 (0)