-
Notifications
You must be signed in to change notification settings - Fork 0
🚀 [Feature]: YAML conversion now possible with ConvertFrom-Yaml and ConvertTo-Yaml #19
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Marius Storhaug (MariusStorhaug)
wants to merge
22
commits into
main
from
feature/2-convert-yaml-functions
Closed
Changes from 20 commits
Commits
Show all changes
22 commits
Select commit
Hold shift + click to select a range
da33548
Add ConvertFrom-Yaml and ConvertTo-Yaml Pester tests and remove place…
MariusStorhaug c3e8c11
Implement ConvertFrom-Yaml with mappings, sequences, scalars, and fro…
MariusStorhaug b4245b4
Implement ConvertTo-Yaml with mappings, sequences, scalars, and quoti…
MariusStorhaug a2e28bc
Update README and example with Yaml usage
MariusStorhaug 4093211
Align scalar resolution with YAML 1.2.2 core schema (case-sensitive t…
MariusStorhaug 80420d3
Drop frontmatter extraction; require valid YAML input and tolerate do…
MariusStorhaug 732b6e6
Remove markdown and frontmatter references from module code and README
MariusStorhaug 84344f7
Fix PSSA and codespell linter warnings: switch to switch-statement in…
MariusStorhaug 2c3d26d
Fix PSScriptAnalyzer violations: add comment help and OutputType decl…
MariusStorhaug a1c9b4e
Fix Build-Docs lint: remove extra bullet indent in ConvertFrom-Yaml d…
MariusStorhaug b4113eb
Fix SourceCode tests: split private helpers into one-function-per-file
MariusStorhaug 8956c19
Fix mapping key parsing: preserve raw text without type resolution, u…
MariusStorhaug 7ce8fd0
Fix empty collection serialization, depth-exceeded indent, and [] / {…
MariusStorhaug da93f35
Add tests for handling various YAML data types and structures in Conv…
MariusStorhaug 03cad1f
Enforce -Depth on nested sequences by routing through ConvertTo-YamlN…
MariusStorhaug 82bedcd
Merge branch 'main' into feature/2-convert-yaml-functions
MariusStorhaug 7030c97
Fix PSUseConsistentWhitespace: add spaces after unary comma operators…
MariusStorhaug 29bba1d
Fix NaN/Infinity as plain strings, sequence extra-dash-space child in…
MariusStorhaug ba4fee0
Support indentless sequences, add unconsumed-lines check, add tests
MariusStorhaug 73aa66f
Add \xHH hex escape parsing, fix PSAvoidLongLines, update help text a…
MariusStorhaug f3e279e
Fix null indentation in ConvertTo-YamlNode, reject tabs in indentatio…
MariusStorhaug 9c0aafb
Fix quote tracking in Find-YamlMappingColon and Remove-YamlInlineComm…
MariusStorhaug File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,19 +1,37 @@ | ||
| <# | ||
| .SYNOPSIS | ||
| This is a general example of how to use the module. | ||
| .SYNOPSIS | ||
| Example usage of the Yaml module: parse YAML to objects and convert objects back to YAML. | ||
| #> | ||
|
|
||
| # Import the module | ||
| Import-Module -Name 'PSModule' | ||
| Import-Module -Name 'Yaml' | ||
|
|
||
| # Define the path to the font file | ||
| $FontFilePath = 'C:\Fonts\CodeNewRoman\CodeNewRomanNerdFontPropo-Regular.tff' | ||
| # 1. Parse a YAML string into a PSCustomObject | ||
| $yaml = @' | ||
| name: Alice | ||
| age: 30 | ||
| skills: | ||
| - PowerShell | ||
| - YAML | ||
| '@ | ||
|
|
||
| # Install the font | ||
| Install-Font -Path $FontFilePath -Verbose | ||
| $person = $yaml | ConvertFrom-Yaml | ||
| $person.name # Alice | ||
| $person.skills[0] # PowerShell | ||
|
|
||
| # List installed fonts | ||
| Get-Font -Name 'CodeNewRomanNerdFontPropo-Regular' | ||
| # 2. Parse YAML as an ordered hashtable | ||
| $hash = $yaml | ConvertFrom-Yaml -AsHashtable | ||
| $hash['age'] # 30 | ||
|
|
||
| # Uninstall the font | ||
| Get-Font -Name 'CodeNewRomanNerdFontPropo-Regular' | Uninstall-Font -Verbose | ||
| # 3. Convert an object to YAML | ||
| [ordered]@{ | ||
| name = 'Alice' | ||
| age = 30 | ||
| skills = @('PowerShell', 'YAML') | ||
| } | ConvertTo-Yaml | ||
|
|
||
| # 4. Force a top-level sequence with -AsArray | ||
| Get-Process | Select-Object -First 3 Name, Id | ConvertTo-Yaml -AsArray | ||
|
|
||
| # 5. Round-trip | ||
| $obj = [ordered]@{ a = 1; b = @('x', 'y') } | ||
| $obj | ConvertTo-Yaml | ConvertFrom-Yaml -AsHashtable |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,66 @@ | ||
| function ConvertFrom-YamlLineStream { | ||
| <# | ||
| .SYNOPSIS | ||
| Splits YAML text into significant lines, dropping comments and blank lines. | ||
|
|
||
| .DESCRIPTION | ||
| Returns an array of `[pscustomobject]` records with `Indent`, `Content`, and `Number` properties. | ||
| - Lines that are empty or whitespace-only are skipped. | ||
| - Lines whose first non-whitespace character is `#` are skipped. | ||
| - Inline comments (` #...` outside quotes) are stripped from the content. | ||
| - Tabs in indentation are not allowed (YAML spec); they are treated as one space here. | ||
| #> | ||
| [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseOutputTypeCorrectly', '', | ||
| Justification = 'Comma-unary operator preserves List type; PSScriptAnalyzer misdetects as Object[].')] | ||
| [CmdletBinding()] | ||
| [OutputType([System.Collections.Generic.List[pscustomobject]])] | ||
| param( | ||
| [Parameter(Mandatory)] | ||
| [AllowEmptyString()] | ||
| [string] $Text | ||
| ) | ||
|
|
||
| $result = [System.Collections.Generic.List[pscustomobject]]::new() | ||
| $normalized = $Text -replace "`r`n", "`n" | ||
| $rawLines = $normalized -split "`n" | ||
|
|
||
| for ($i = 0; $i -lt $rawLines.Count; $i++) { | ||
| $raw = $rawLines[$i] | ||
|
|
||
| if ([string]::IsNullOrWhiteSpace($raw)) { | ||
| continue | ||
| } | ||
|
|
||
| # Compute indent (spaces before first non-space). | ||
| $indent = 0 | ||
| while ($indent -lt $raw.Length -and ($raw[$indent] -eq ' ' -or $raw[$indent] -eq "`t")) { | ||
| $indent++ | ||
| } | ||
|
|
||
| $content = $raw.Substring($indent) | ||
|
|
||
| if ($content.StartsWith('#')) { | ||
| continue | ||
| } | ||
|
|
||
| # Strip inline comments while respecting single/double quotes. | ||
| $stripped = Remove-YamlInlineComment -Line $content | ||
| if ([string]::IsNullOrWhiteSpace($stripped)) { | ||
| continue | ||
| } | ||
|
|
||
| # Skip YAML document markers: --- (start) and ... (end). | ||
| $trimmed = $stripped.Trim() | ||
| if ($trimmed -eq '---' -or $trimmed -eq '...') { | ||
| continue | ||
| } | ||
|
|
||
| $result.Add([pscustomobject]@{ | ||
| Indent = $indent | ||
| Content = $stripped.TrimEnd() | ||
| Number = $i + 1 | ||
| }) | ||
| } | ||
|
|
||
| return , $result | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,88 @@ | ||
| function ConvertFrom-YamlMapping { | ||
| <# | ||
| .SYNOPSIS | ||
| Parses a YAML block-style mapping into a PSCustomObject or OrderedDictionary. | ||
| #> | ||
| [CmdletBinding()] | ||
| [OutputType([System.Collections.Specialized.OrderedDictionary], [pscustomobject])] | ||
| param( | ||
| [Parameter(Mandatory)] [pscustomobject] $Context, | ||
| [Parameter(Mandatory)] [int] $Indent, | ||
| [Parameter(Mandatory)] [int] $Depth | ||
| ) | ||
|
|
||
| $lines = $Context.Lines | ||
| $map = [ordered]@{} | ||
|
|
||
| while ($Context.Index -lt $lines.Count) { | ||
| $line = $lines[$Context.Index] | ||
| if ($line.Indent -lt $Indent) { break } | ||
| if ($line.Indent -gt $Indent) { | ||
| throw "ConvertFrom-Yaml: unexpected indentation at line $($line.Number)." | ||
| } | ||
| if ($line.Content.StartsWith('- ') -or $line.Content -eq '-') { | ||
| # A sequence at the same indent as a mapping key is a sibling, not part of mapping. | ||
| break | ||
| } | ||
|
|
||
| $colonIdx = Find-YamlMappingColon -Content $line.Content | ||
| if ($colonIdx -lt 0) { | ||
| throw "ConvertFrom-Yaml: expected mapping key at line $($line.Number): '$($line.Content)'." | ||
| } | ||
|
|
||
| $rawKey = $line.Content.Substring(0, $colonIdx).Trim() | ||
| if ($rawKey.Length -ge 2 -and $rawKey[0] -eq "'" -and $rawKey[-1] -eq "'") { | ||
| $key = ($rawKey.Substring(1, $rawKey.Length - 2)) -replace "''", "'" | ||
| } elseif ($rawKey.Length -ge 2 -and $rawKey[0] -eq '"' -and $rawKey[-1] -eq '"') { | ||
| $key = Expand-YamlDoubleQuoted -Text ($rawKey.Substring(1, $rawKey.Length - 2)) | ||
| } else { | ||
| $key = $rawKey | ||
| } | ||
| $rest = $line.Content.Substring($colonIdx + 1).Trim() | ||
|
|
||
| $Context.Index++ | ||
|
|
||
| if ($rest.Length -gt 0) { | ||
| if ($rest -ceq '{}') { | ||
| $map[$key] = if ($Context.AsHashtable) { [ordered]@{} } else { [pscustomobject][ordered]@{} } | ||
| } elseif ($rest -ceq '[]') { | ||
| $map[$key] = @() | ||
| } else { | ||
| $map[$key] = ConvertFrom-YamlScalar -Raw $rest | ||
| } | ||
| continue | ||
| } | ||
|
|
||
| # Value on subsequent indented lines (mapping or sequence) or null. | ||
| if ($Context.Index -ge $lines.Count) { | ||
| $map[$key] = $null | ||
| continue | ||
| } | ||
|
|
||
| $next = $lines[$Context.Index] | ||
| if ($next.Indent -lt $Indent) { | ||
| $map[$key] = $null | ||
| continue | ||
| } | ||
| if ($next.Indent -eq $Indent) { | ||
| # Indentless sequences: YAML allows a sequence to start at the same indent as the | ||
| # parent mapping key (e.g. "key:\n- a\n- b"). Parse these as the key's value. | ||
| if ($next.Content.StartsWith('- ') -or $next.Content -eq '-') { | ||
| $map[$key] = ConvertFrom-YamlSequence -Context $Context -Indent $Indent -Depth ($Depth + 1) | ||
| continue | ||
| } | ||
| $map[$key] = $null | ||
| continue | ||
| } | ||
|
|
||
| $childIndent = $next.Indent | ||
| $value = ConvertFrom-YamlNode -Context $Context -Indent $childIndent -Depth ($Depth + 1) | ||
| $map[$key] = $value | ||
| } | ||
|
|
||
| if ($Context.AsHashtable) { | ||
| return $map | ||
| } | ||
|
|
||
| return [pscustomobject]$map | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| function ConvertFrom-YamlNode { | ||
| <# | ||
| .SYNOPSIS | ||
| Recursive-descent parser for the YAML line stream produced by ConvertFrom-YamlLineStream. | ||
|
|
||
| .DESCRIPTION | ||
| Reads a node starting at the current line index and at the given indentation level. | ||
| Returns either a mapping (PSCustomObject or OrderedDictionary), a sequence (array), | ||
| or a scalar. | ||
| #> | ||
| [CmdletBinding()] | ||
| param( | ||
| [Parameter(Mandatory)] | ||
| [pscustomobject] $Context, | ||
|
|
||
| [Parameter(Mandatory)] | ||
| [int] $Indent, | ||
|
|
||
| [Parameter(Mandatory)] | ||
| [int] $Depth | ||
| ) | ||
|
|
||
| if ($Depth -gt $Context.MaxDepth) { | ||
| throw "ConvertFrom-Yaml: maximum nesting depth ($($Context.MaxDepth)) exceeded." | ||
| } | ||
|
|
||
| $lines = $Context.Lines | ||
| if ($Context.Index -ge $lines.Count) { | ||
| return $null | ||
| } | ||
|
|
||
| $current = $lines[$Context.Index] | ||
|
|
||
| # Determine node kind from the first line at this indent. | ||
| if ($current.Content.StartsWith('- ') -or $current.Content -eq '-') { | ||
| return ConvertFrom-YamlSequence -Context $Context -Indent $Indent -Depth $Depth | ||
| } | ||
|
|
||
| return ConvertFrom-YamlMapping -Context $Context -Indent $Indent -Depth $Depth | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.