Private/Get-HDTStepKey.ps1
|
function Get-HDTStepKey { <# .SYNOPSIS Finds one key inside a step's own lines, and the line a new key would go after. .DESCRIPTION THE SHARED HALF OF EVERY "SET A PROPERTY" EDIT. Setting `disabled`, `continueOnError` or `condition` is the same three-way splice each time - rewrite the line if the key is there, insert one if it is not, and know exactly which lines count as this step's - so it is written once and the cmdlets above it only decide the value. A GROUP'S OWN KEYS STOP AT ITS `steps:`. Get-HDTStepBlock hands back a block that covers the whole group INCLUDING the steps nested inside it, which is right for moving and copying and wrong for this: a group whose first step already carries `disabled: true` would otherwise look like a group that is already switched off, and setting the group's flag would rewrite the step's line instead. The scan therefore stops at the first nested entry or at `steps:`, whichever comes first. A NEW KEY GOES DIRECTLY UNDER `type:`, WHERE THE ENGINE'S OWN DOCUMENTS PUT IT. What a step is comes first, how it behaves comes next, and the per-type properties follow - which is the order every sample sequence in this repository is written in, and the order an administrator scanning a diff expects. A group has no `type:`, so its key goes after the last line that is still the group's own. IT RETURNS AN INDEX, NOT A LINE. The caller does the splicing, because the caller is the one that knows whether it is inserting, rewriting or removing - and a helper that did all three would be a second copy of the three cmdlets that call it. .PARAMETER Line The document, already split into lines. .PARAMETER Block One block from Get-HDTStepBlock. .PARAMETER Key The YAML key to find, exactly as it is written in the file. .INPUTS None. This command does not accept pipeline input. .OUTPUTS System.Management.Automation.PSCustomObject: Index the line the key is on, or -1 when the step has no such key Insert the line a new one would go directly after Indent the column this step's keys are written at .EXAMPLE Get-HDTStepKey -Line $line -Block $block -Key 'disabled' #> [CmdletBinding()] [OutputType([pscustomobject])] param( [Parameter(Mandatory = $true, Position = 0)] [AllowEmptyCollection()] [AllowEmptyString()] [string[]] $Line, [Parameter(Mandatory = $true, Position = 1)] [ValidateNotNull()] [object] $Block, [Parameter(Mandatory = $true, Position = 2)] [ValidateNotNullOrEmpty()] [string] $Key ) Set-StrictMode -Version Latest $ErrorActionPreference = 'Stop' # A key sits two columns in from the dash that opened the entry, which is # what `- name: X` / ` type: Y` means as an indentation. $indent = [int] $Block.Indent + 2 $index = -1 $typeAt = -1 $lastOwn = [int] $Block.Entry for ($i = [int] $Block.Entry; $i -le [int] $Block.End; $i++) { $text = $Line[$i] # The nested list a group holds is not the group's own text, and neither # is anything after it. if ($i -gt [int] $Block.Entry -and $text -match '^\s*-\s') { break } if ($text -match '^\s*steps:\s*$') { break } if ([string]::IsNullOrWhiteSpace($text)) { continue } if ($text -match '^\s*#') { continue } # Either the entry line itself (`- name: X`) or a key under it. $name = '' if ($i -eq [int] $Block.Entry -and $text -match '^\s*-\s+([A-Za-z][\w-]*):') { $name = $Matches[1] } elseif ($text -match ('^\s{{{0}}}([A-Za-z][\w-]*):' -f $indent)) { $name = $Matches[1] } else { # Deeper than this step's keys - a nested mapping's contents, which # this step owns but does not name. continue } $lastOwn = $i if ($name -eq $Key) { $index = $i } if ($name -eq 'type') { $typeAt = $i } } $insert = $lastOwn if ($typeAt -ge 0) { $insert = $typeAt } return [pscustomobject] @{ Index = $index Insert = $insert Indent = $indent } } |