src/Engine/Entry.ps1
|
# Entry.ps1 — raw JSON → validated module entry, and file-level parsing. # Normalise one raw module entry into the rich object the rest of psmm uses. # Invalid Install/Mode values degrade to the defaults with an issue recorded — # a broken entry must never take the whole config file down. function Resolve-PSMMEntry { [CmdletBinding()] param( [Parameter(Mandatory)] $Raw, [Parameter(Mandatory)][string]$Source, [Parameter(Mandatory)][bool]$Writable ) $validInstall = 'CheckOnly', 'IfMissing', 'Latest' $validMode = 'Load', 'InstallOnly', 'Ignore' $issues = [System.Collections.Generic.List[string]]::new() $name = [string]$Raw.Name if ([string]::IsNullOrWhiteSpace($name)) { $issues.Add('Missing Name') } $install = if ($Raw.PSObject.Properties['Install'] -and $Raw.Install) { [string]$Raw.Install } else { 'IfMissing' } if ($install -notin $validInstall) { $issues.Add("Invalid Install '$install' (using IfMissing)"); $install = 'IfMissing' } $mode = if ($Raw.PSObject.Properties['Mode'] -and $Raw.Mode) { [string]$Raw.Mode } else { 'Load' } if ($mode -notin $validMode) { $issues.Add("Invalid Mode '$mode' (using Load)"); $mode = 'Load' } # Optional version pin: exact ("1.2.3"), exact prerelease ("1.2.3-beta4") # or NuGet range ("[1.0,2.0)"). # # The prerelease label is part of the pin (gh#6): 0.1.0-beta8 and 0.1.0 are # different releases that share one [version]. It is kept SEPARATE from the # base version because Import-Module -RequiredVersion is typed [version] # and throws on a label - see Import-PSMMModuleTimed. $version = $null if ($Raw.PSObject.Properties['Version'] -and $Raw.Version) { $version = ([string]$Raw.Version).Trim() } $pinnedExact = $false $pinnedBase = $null $pinnedLabel = '' if ($version) { if ($version -match '^(?<base>\d+(\.\d+){1,3})(-(?<label>[A-Za-z0-9][A-Za-z0-9.-]*))?$') { $pinnedExact = $true $pinnedBase = $Matches['base'] $pinnedLabel = "$($Matches['label'])" } elseif ($version -notmatch '^[\[\(][0-9\.\,\s\*\-A-Za-z]*[\]\)]$') { $issues.Add("Invalid Version '$version' (ignoring pin)") $version = $null } } # Optional prerelease opt-in (gh#6): "Prerelease": true lets install/update # and the pin picker consider prerelease versions from the gallery. $allowPre = $false if ($Raw.PSObject.Properties['Prerelease'] -and $null -ne $Raw.Prerelease) { try { $allowPre = [bool]$Raw.Prerelease } catch { $issues.Add("Invalid Prerelease '$($Raw.Prerelease)' (using false)") } } [pscustomobject]@{ Name = $name FriendlyName = if ($Raw.FriendlyName) { [string]$Raw.FriendlyName } else { $name } Description = [string]$Raw.Description Install = $install Mode = $mode Version = $version PinnedExact = $pinnedExact PinnedBaseVersion = $pinnedBase # the pin without its prerelease label PinnedPrerelease = $pinnedLabel # '' unless the pin names a prerelease AllowPrerelease = $allowPre # config "Prerelease": true Source = $Source Writable = $Writable Issues = $issues.ToArray() Installed = $false InstalledVersion = $null InstalledPrerelease = '' # label of the newest installed copy ('' = stable) InstalledVersions = @() # every installed version (duplicate-cleanup feature) InstallScope = $null # CurrentUser | AllUsers | mixed | $null (unknown) Loaded = $false LoadedVersion = $null LoadedPrerelease = '' LatestVersion = $null LatestPrerelease = '' UpdateAvailable = $false ImportMs = $null # measured import duration (startup / UI load) } } # Parse one config file's JSON into its file-level shape. Throws on bad JSON — # the caller records the warning and skips the file. function ConvertFrom-PSMMJson { [CmdletBinding()] param([Parameter(Mandatory)][string]$Json) $obj = $Json | ConvertFrom-Json -ErrorAction Stop [pscustomobject]@{ Legend = $obj._legend HasEnabled = [bool]$obj.PSObject.Properties['Enabled'] Enabled = if ($obj.PSObject.Properties['Enabled'] -and $null -ne $obj.Enabled) { [bool]$obj.Enabled } else { $true } Includes = if ($obj.PSObject.Properties['Includes']) { @($obj.Includes | Where-Object { $_ }) } else { @() } Modules = @($obj.Modules) } } |