src/handlers/qconf/entry-types.ps1
|
#requires -version 7.0 function Get-ConfigEntryTemplate { param( $Entry ) if ($Entry -isnot [System.Collections.IDictionary]) { return $null } if (-not $Entry.Contains('_template')) { return $null } $template = $Entry._template if ($template -is [System.Collections.IDictionary]) { return $template } if ($template -is [string]) { # Short form: "appsettings:{filepath}" → @{ type = 'appconfig'; file = ... } if ($template -match '^(?i)appsettings:(.+)$') { $file = $Matches[1].Trim() if ([string]::IsNullOrWhiteSpace($file)) { throw "Config entry template 'appsettings:' requires a file path." } return @{ type = 'appconfig' file = $file } } # Short form: "dotenv:{filepath}" → @{ type = 'dotenv'; file = ... } if ($template -match '^(?i)dotenv:(.+)$') { $file = $Matches[1].Trim() if ([string]::IsNullOrWhiteSpace($file)) { throw "Config entry template 'dotenv:' requires a file path." } return @{ type = 'dotenv' file = $file } } throw "Unknown config entry template '$template'." } return $null } function Resolve-ConfigEntryFile { param( $Entry, [Parameter(Mandatory = $true)] [System.Collections.IDictionary]$Template, [Parameter(Mandatory = $true)] [string]$TypeName ) $file = $Template.file if ($file -isnot [string] -or [string]::IsNullOrWhiteSpace($file)) { throw "Config entry type '$TypeName' requires a file path." } if ([System.IO.Path]::IsPathRooted($file)) { return $file } $baseDir = if ($Entry._baseDir) { [string]$Entry._baseDir } else { (Get-Location).Path } return [System.IO.Path]::GetFullPath((Join-Path $baseDir $file)) } function Get-ConfigEntryTemplateFile { param( [Parameter(Mandatory = $true)] $Entry, [Parameter(Mandatory = $true)] [string]$TypeName ) $template = Get-ConfigEntryTemplate -Entry $Entry if ($null -eq $template) { throw "Config entry has no _template." } return Resolve-ConfigEntryFile -Entry $Entry -Template $template -TypeName $TypeName } function Set-AppConfigOption { param( [Parameter(Mandatory = $true)] [string]$File, $Values ) if ($Values -isnot [System.Collections.IDictionary]) { throw "appconfig option value must be a hashtable of setting keys." } $directory = Split-Path -Parent $File foreach ($key in @($Values.Keys)) { if ("$key".StartsWith('__')) { continue } $settingValue = resolve-value $Values[$key] -dir $directory set-appsettings -file $File -path $key -value $settingValue } } function Find-ActiveEnvOption { param( [Parameter(Mandatory = $true)] [string]$File, [Parameter(Mandatory = $true)] $Options ) $active = $null $valueObject = [ordered]@{} foreach ($optionSet in $Options.Keys) { $option = $Options[$optionSet] if ($option -isnot [System.Collections.IDictionary]) { continue } $isMatch = $true foreach ($key in @($option.Keys)) { if ("$key".StartsWith('__')) { continue } if (-not $valueObject.Contains($key)) { $valueObject[$key] = get-envsetting $key $File } $currentValue = $valueObject[$key] $optionValue = $option[$key] if ($null -eq $currentValue) { $isMatch = $false continue } if ($isMatch -and $currentValue -is [string] -and $currentValue -ne $optionValue -and -not (test-isSpecialValue $optionValue)) { $isMatch = $false } } if ($isMatch) { $active = $optionSet break } } return @{ Value = $valueObject; Active = $active } } function Set-DotEnvOption { param( [Parameter(Mandatory = $true)] [string]$File, $Values ) if ($Values -isnot [System.Collections.IDictionary]) { throw "dotenv option value must be a hashtable of environment variable keys." } $directory = Split-Path -Parent $File foreach ($key in @($Values.Keys)) { if ("$key".StartsWith('__')) { continue } $settingValue = resolve-value $Values[$key] -dir $directory set-envsetting $key $settingValue $File } } function Get-ConfigEntryTypeCommands { <# .SYNOPSIS Built-in get/set implementations for Entry._template types. #> return [ordered]@{ appconfig = @{ get = { param($ctx, $options, $_context) $file = Get-ConfigEntryTemplateFile -Entry $_context.self -TypeName 'appconfig' Find-ActiveOption -file $file -options $options } set = { param($ctx, $key, $value, $_context) $file = Get-ConfigEntryTemplateFile -Entry $_context.self -TypeName 'appconfig' Set-AppConfigOption -File $file -Values $value } } dotenv = @{ get = { param($ctx, $options, $_context) $file = Get-ConfigEntryTemplateFile -Entry $_context.self -TypeName 'dotenv' Find-ActiveEnvOption -File $file -Options $options } set = { param($ctx, $key, $value, $_context) $file = Get-ConfigEntryTemplateFile -Entry $_context.self -TypeName 'dotenv' Set-DotEnvOption -File $file -Values $value } } } } function Add-ConfigEntryTypeCommands { <# .SYNOPSIS Fill in get and set from Entry._template when the map did not supply them. .DESCRIPTION Accepts `_template` as a hashtable (`type`/`file`) or short string (`appsettings:{filepath}` or `dotenv:{filepath}`). Leaves an author-supplied get or set in place. #> param( $Entry ) if ($Entry -isnot [System.Collections.IDictionary]) { return } $template = Get-ConfigEntryTemplate -Entry $Entry if ($null -eq $template -or -not $template.Contains('type') -or -not $template.type) { return } $needsGet = $Entry.get -isnot [scriptblock] $needsSet = $Entry.set -isnot [scriptblock] if (-not $needsGet -and -not $needsSet) { return } $typeName = [string]$template.type $typeCommands = Get-ConfigEntryTypeCommands if (-not $typeCommands.Contains($typeName)) { throw "Unknown config entry type '$typeName'." } $null = Resolve-ConfigEntryFile -Entry $Entry -Template $template -TypeName $typeName $commands = $typeCommands[$typeName] if ($needsGet) { $Entry.get = $commands.get } if ($needsSet) { $Entry.set = $commands.set } } |