Private/ConvertFrom-QAFrameworkAttributeValue.ps1
|
function ConvertFrom-QAFrameworkAttributeValue { <# .SYNOPSIS Normalises a single C# attribute argument expression into a PowerShell value. .DESCRIPTION Handles string literals (regular and verbatim), booleans, integers, enum member references such as RunOn.All or DiagnosticRunType.Before, and nameof(...) expressions. Enum references are reduced to their member name only. .PARAMETER Expression The raw argument expression. .OUTPUTS String, Boolean or Int32 depending on the expression. #> [CmdletBinding()] [OutputType([object])] param( [Parameter(Mandatory = $true)] [AllowEmptyString()] [AllowNull()] [string]$Expression ) if ($null -eq $Expression) { return $null } $value = $Expression.Trim() if ($value -eq '') { return '' } # Verbatim string: @"..." (an escaped "" becomes a single "). if ($value.StartsWith('@"') -and $value.EndsWith('"') -and $value.Length -ge 3) { return $value.Substring(2, $value.Length - 3).Replace('""', '"') } # Regular string literal: "..." if ($value.StartsWith('"') -and $value.EndsWith('"') -and $value.Length -ge 2) { $inner = $value.Substring(1, $value.Length - 2) return [System.Text.RegularExpressions.Regex]::Unescape($inner) } # nameof(Something) -> Something if ($value -match '^nameof\s*\(\s*(.+?)\s*\)$') { return ($Matches[1] -split '\.')[-1] } if ($value -match '^(?i:true)$') { return $true } if ($value -match '^(?i:false)$') { return $false } $intValue = 0 if ([int]::TryParse($value, [ref]$intValue)) { return $intValue } # Enum member reference such as RunOn.All or DiagnosticRunType.Before. if ($value -match '^[A-Za-z_][\w]*(\.[A-Za-z_][\w]*)+$') { return ($value -split '\.')[-1] } return $value } function ConvertTo-QAFrameworkAttributeArgumentMap { <# .SYNOPSIS Splits attribute arguments into positional values and named values. .DESCRIPTION C# attributes allow named property/field initialisers (Name = value) after the positional constructor arguments. This helper separates the two forms and normalises every value via ConvertFrom-QAFrameworkAttributeValue. .PARAMETER ArgumentText The raw text between the attribute's outer parentheses. .OUTPUTS Hashtable with 'Positional' (object[]) and 'Named' (hashtable, case-insensitive). #> [CmdletBinding()] [OutputType([hashtable])] param( [Parameter(Mandatory = $true)] [AllowEmptyString()] [AllowNull()] [string]$ArgumentText ) $positional = [System.Collections.Generic.List[object]]::new() $named = [System.Collections.Generic.Dictionary[string, object]]::new([System.StringComparer]::OrdinalIgnoreCase) foreach ($argument in (Split-QAFrameworkAttributeArgument -ArgumentText $ArgumentText)) { # Named property initialiser (Name = value) or C# named argument (name: value). if ($argument -match '^\s*([A-Za-z_]\w*)\s*(?:=|:)\s*(.+)$') { $named[$Matches[1]] = ConvertFrom-QAFrameworkAttributeValue -Expression $Matches[2] } else { $positional.Add((ConvertFrom-QAFrameworkAttributeValue -Expression $argument)) } } return @{ Positional = $positional.ToArray() Named = $named } } |