private/Get-WtwWorktreeAliases.ps1
|
function Get-WtwWorktreeAliases { <# .SYNOPSIS Optional typed aliases stored on a worktree entry (not the derived alias-task names). #> param([AllowNull()] [PSObject] $Worktree) $result = @() if (-not $Worktree) { return , $result } if ((Get-WtwPropertyNames -Object $Worktree) -contains 'aliases' -and $Worktree.aliases) { $result = @($Worktree.aliases) } elseif ((Get-WtwPropertyNames -Object $Worktree) -contains 'alias' -and $Worktree.alias) { $result = @($Worktree.alias) } return , @($result | ForEach-Object { "$_".Trim() } | Where-Object { $_ }) } function ConvertTo-WtwLookupKey { <# .SYNOPSIS Normalise a search/alias string so spaces, hyphens, and slashes match. #> param([AllowNull()] [string] $Value) if ([string]::IsNullOrWhiteSpace($Value)) { return '' } $t = $Value.Trim() $t = $t -replace '^[\p{So}\p{Sk}\p{Cn}\s]+', '' return ($t.ToLowerInvariant() -replace '[-_/\s]+', ' ').Trim() } function Join-WtwTargetName { <# .SYNOPSIS Join leftover positionals so ``wtw go onboarding video`` keeps the space. #> param([AllowNull()] [string[]] $Parts) if (-not $Parts) { return '' } return (@($Parts | ForEach-Object { "$_".Trim() } | Where-Object { $_ }) -join ' ') } function ConvertTo-WtwShellAliasName { <# .SYNOPSIS Turn a typed alias into a shell-safe name (spaces become hyphens). #> param([AllowNull()] [string] $Alias) if ([string]::IsNullOrWhiteSpace($Alias)) { return '' } return (($Alias.Trim() -replace '\s+', '-')) } function Test-WtwReservedShellAliasName { <# .SYNOPSIS True when a generated alias would shadow wtw, pwsh, or an editor CLI. #> param([AllowNull()] [string] $Name) $key = ConvertTo-WtwLookupKey $Name return $key -in @( 'wtw', 'pwsh', 'powershell', 'cursor', 'code', 'antigravity', 'windsurf', 'codium', 'git', 'ssh', 'sudo', 'cd', 'ls' ) } function Test-WtwLookupMatch { param( [string] $Query, [AllowNull()] [string] $Candidate, [ValidateSet('Exact', 'Prefix', 'Substring')] [string] $Mode ) $q = ConvertTo-WtwLookupKey $Query $c = ConvertTo-WtwLookupKey $Candidate if (-not $q -or -not $c) { return $false } switch ($Mode) { 'Exact' { return $q -eq $c } 'Prefix' { return $c.StartsWith($q) } 'Substring' { return $c.Contains($q) } } return $false } function Test-WtwAliasClearToken { param([AllowNull()] [string[]] $Value) $first = @($Value | Where-Object { -not [string]::IsNullOrWhiteSpace($_) } | Select-Object -First 1) if ($first.Count -eq 0) { return $false } $token = ConvertTo-WtwLookupKey "$($first[0])" return $token -in @('-', 'none', 'off', 'clear') } function Get-WtwMatchingWorktrees { <# .SYNOPSIS Collect worktree targets whose task / alias / branch / pretty name matches. #> param( [Parameter(Mandatory)] [PSObject] $Registry, [string] $RestrictRepo, [Parameter(Mandatory)] [string] $Name, [ValidateSet('Exact', 'Prefix', 'Substring')] [string] $Mode, [ValidateSet('Task', 'Alias', 'Branch', 'Pretty')] [string] $Field ) $found = @() foreach ($repoName in (Get-WtwPropertyNames -Object $Registry.repos)) { if ($RestrictRepo -and $repoName -ne $RestrictRepo) { continue } $repo = $Registry.repos.$repoName if (-not $repo.worktrees) { continue } foreach ($taskName in (Get-WtwPropertyNames -Object $repo.worktrees)) { $wt = $repo.worktrees.$taskName $candidates = switch ($Field) { 'Task' { @($taskName) } 'Alias' { @(Get-WtwWorktreeAliases $wt) } 'Branch' { @(Get-WtwPropertyValue -Object $wt -Name 'branch') } 'Pretty' { @(Get-WtwPropertyValue -Object $wt -Name 'prettyName') } } $hit = $false foreach ($candidate in $candidates) { if (Test-WtwLookupMatch -Query $Name -Candidate $candidate -Mode $Mode) { $hit = $true break } } if ($hit) { $found += [PSCustomObject]@{ RepoName = $repoName RepoEntry = $repo TaskName = $taskName WorktreeEntry = $wt } } } } return @($found) } function Test-WtwWorktreeAliasCollision { <# .SYNOPSIS Return $true (and write the error) when a worktree alias collides globally. #> param( [Parameter(Mandatory)] [PSObject] $Registry, [Parameter(Mandatory)] [string] $RepoName, [Parameter(Mandatory)] [string] $TaskName, [AllowEmptyCollection()] [string[]] $Aliases ) foreach ($newAlias in @($Aliases)) { $key = ConvertTo-WtwLookupKey $newAlias if (-not $key) { continue } foreach ($existingName in (Get-WtwPropertyNames -Object $Registry.repos)) { $existingRepo = $Registry.repos.$existingName if ((ConvertTo-WtwLookupKey $existingName) -eq $key) { Write-Error "Alias '$newAlias' collides with repo '$existingName'." return $true } foreach ($repoAlias in (Get-WtwRepoAliases $existingRepo)) { if ((ConvertTo-WtwLookupKey $repoAlias) -eq $key) { Write-Error "Alias '$newAlias' is already used by repo '$existingName'." return $true } } if (-not $existingRepo.worktrees) { continue } foreach ($task in (Get-WtwPropertyNames -Object $existingRepo.worktrees)) { if ($existingName -eq $RepoName -and $task -eq $TaskName) { continue } if ((ConvertTo-WtwLookupKey $task) -eq $key) { Write-Error "Alias '$newAlias' collides with worktree '$existingName/$task'." return $true } foreach ($wtAlias in (Get-WtwWorktreeAliases $existingRepo.worktrees.$task)) { if ((ConvertTo-WtwLookupKey $wtAlias) -eq $key) { Write-Error "Alias '$newAlias' is already used by worktree '$existingName/$task'." return $true } } } } } return $false } |