Private/Resolve-DhNavDeclaration.ps1
|
<# Nav declaration resolver — turns whatever nav parameters a caller supplied into the canonical (Path, Scope) pair the exporter and runtime consume. Every nav-aware cmdlet calls this exactly once. Keeping the mapping here rather than repeating it across 16 cmdlets is deliberate: the 1.x bug this release exists to fix (readme-dev gotcha #26) was caused by the same concept being implemented slightly differently in several places. v2.0.0 API : -NavPath 'A/B/C' + -NavScope Exact|Subtree|Global v1.x compat API : -NavGroup / -NavSubGroup (kept indefinitely) #> function Resolve-DhNavDeclaration { <# .SYNOPSIS Resolve nav parameters to a canonical path + scope. .PARAMETER NavPath v2 path, '/'-separated. '//' escapes a literal '/'. .PARAMETER NavScope Exact / Subtree / Global. When omitted, a sensible default is chosen from ItemKind (see below). .PARAMETER NavGroup v1.x compat: primary group label. .PARAMETER NavSubGroup v1.x compat: second-level label under NavGroup. .PARAMETER ItemKind 'Block' or 'Table'. Drives the compat defaults, because 1.x meant different things by "no subgroup" for the two: Block : content shown across the whole group -> Subtree Table : one specific view -> Exact In 2.0.0 a table is a node like any other, so the compat shim appends its TableId as a leaf segment to preserve its own menu entry. .PARAMETER TableId Required when ItemKind is 'Table' and the compat API is used. .OUTPUTS [hashtable] @{ Path = [string[]]; Scope = [string] } .NOTES Supplying BOTH -NavPath and -NavGroup/-NavSubGroup is a hard error. Silent precedence between two ways of saying the same thing is exactly how the 1.x nav became three competing mechanisms. #> [CmdletBinding()] param( [string] $NavPath = '', [string] $NavScope = '', [string] $NavGroup = '', [string] $NavSubGroup = '', [ValidateSet('Block','Table')] [string] $ItemKind = 'Block', [string] $TableId = '', [string] $Context = '' ) $hasV2 = -not [string]::IsNullOrWhiteSpace($NavPath) $hasV1 = (-not [string]::IsNullOrWhiteSpace($NavGroup)) -or (-not [string]::IsNullOrWhiteSpace($NavSubGroup)) if ($hasV2 -and $hasV1) { $where = if ($Context) { "$Context : " } else { '' } throw ("${where}-NavPath cannot be combined with -NavGroup / -NavSubGroup. " + "Use -NavPath '$NavGroup$(if($NavSubGroup){"/$NavSubGroup"})' on its own, " + "or keep the v1 parameters. See readme-dev.md section 15.") } if ((-not [string]::IsNullOrWhiteSpace($NavSubGroup)) -and [string]::IsNullOrWhiteSpace($NavGroup)) { $where = if ($Context) { "$Context : " } else { '' } throw "${where}-NavSubGroup requires -NavGroup. A subgroup with no parent has no place in the menu." } # ── v2 path supplied ──────────────────────────────────────────────────── if ($hasV2) { $segments = ConvertFrom-DhNavPath $NavPath $scope = if ($NavScope) { $NavScope } else { 'Exact' } return @{ Path = @($segments); Scope = $scope } } # ── v1 compat ─────────────────────────────────────────────────────────── if ($hasV1) { $segments = [System.Collections.Generic.List[string]]::new() [void]$segments.Add($NavGroup.Trim()) if (-not [string]::IsNullOrWhiteSpace($NavSubGroup)) { [void]$segments.Add($NavSubGroup.Trim()) } if ($ItemKind -eq 'Table') { # 1.x gave every grouped table its own subnav link. Preserve that by # appending the TableId as a leaf, keyed on TableId (the only value # Add-DhTable enforces as unique) rather than the free-form Title. if ([string]::IsNullOrWhiteSpace($TableId)) { throw 'Resolve-DhNavDeclaration: ItemKind Table requires -TableId.' } [void]$segments.Add($TableId) $scope = if ($NavScope) { $NavScope } else { 'Exact' } } else { # 1.x blocks were visible across their whole group. $scope = if ($NavScope) { $NavScope } else { 'Subtree' } } return @{ Path = @($segments); Scope = $scope } } # ── Nothing supplied ──────────────────────────────────────────────────── if ($NavScope) { return @{ Path = @(); Scope = $NavScope } } if ($ItemKind -eq 'Table') { # 1.x flat nav: an ungrouped table got its own link in the primary bar # and only one showed at a time. Giving it a single-segment path keyed on # TableId reproduces that exactly under the uniform model. Without this a # plain report would render every table stacked at once - a regression in # the commonest case of all. if ([string]::IsNullOrWhiteSpace($TableId)) { throw 'Resolve-DhNavDeclaration: ItemKind Table requires -TableId.' } return @{ Path = @($TableId); Scope = 'Exact' } } # 1.x: an ungrouped BLOCK was visible on every panel. return @{ Path = @(); Scope = 'Global' } } |