@@ -150,6 +150,215 @@ Describe 'Register/Unregister-PSCommandHelperPrompt' {
150150 }
151151}
152152
153+ Describe ' Prompt handler: reverse alias lookup' {
154+ BeforeAll {
155+ InModuleScope PSCommandHelper {
156+ $map = Get-BashToPowerShellMap
157+ $script :TestAliasedMap = @ {}
158+ foreach ($entry in ($map | Where-Object { $_.Type -eq ' Aliased' })) {
159+ $baseCmd = ($entry.Bash -split ' \s+' )[0 ]
160+ if (-not $script :TestAliasedMap.ContainsKey ($baseCmd )) {
161+ $script :TestAliasedMap [$baseCmd ] = @ ()
162+ }
163+ $script :TestAliasedMap [$baseCmd ] += $entry
164+ }
165+ }
166+ }
167+
168+ It ' rm is in the aliased map' {
169+ InModuleScope PSCommandHelper {
170+ $script :TestAliasedMap.ContainsKey (' rm' ) | Should - BeTrue
171+ }
172+ }
173+
174+ It ' Remove-Item reverse-resolves to rm which is in the aliased map' {
175+ $aliases = Get-Alias - Definition ' Remove-Item' - ErrorAction SilentlyContinue
176+ $aliasNames = $aliases | ForEach-Object { $_.Name }
177+ $aliasNames | Should - Contain ' rm'
178+ }
179+
180+ It ' Get-ChildItem reverse-resolves to ls which is in the aliased map' {
181+ $aliases = Get-Alias - Definition ' Get-ChildItem' - ErrorAction SilentlyContinue
182+ $aliasNames = $aliases | ForEach-Object { $_.Name }
183+ $aliasNames | Should - Contain ' ls'
184+ }
185+
186+ It ' Copy-Item reverse-resolves to cp which is in the aliased map' {
187+ InModuleScope PSCommandHelper {
188+ $aliases = Get-Alias - Definition ' Copy-Item' - ErrorAction SilentlyContinue
189+ $found = $false
190+ foreach ($a in $aliases ) {
191+ if ($script :TestAliasedMap.ContainsKey ($a.Name )) {
192+ $found = $true
193+ break
194+ }
195+ }
196+ $found | Should - BeTrue
197+ }
198+ }
199+
200+ It ' Move-Item reverse-resolves to mv which is in the aliased map' {
201+ InModuleScope PSCommandHelper {
202+ $aliases = Get-Alias - Definition ' Move-Item' - ErrorAction SilentlyContinue
203+ $found = $false
204+ foreach ($a in $aliases ) {
205+ if ($script :TestAliasedMap.ContainsKey ($a.Name )) {
206+ $found = $true
207+ break
208+ }
209+ }
210+ $found | Should - BeTrue
211+ }
212+ }
213+ }
214+
215+ Describe ' Flag-aware matching' {
216+ BeforeAll {
217+ InModuleScope PSCommandHelper {
218+ $map = Get-BashToPowerShellMap
219+ $script :TestRmEntries = $map | Where-Object { ($_.Bash -split ' \s+' )[0 ] -eq ' rm' -and $_.Type -eq ' Aliased' }
220+ $script :TestLsEntries = $map | Where-Object { ($_.Bash -split ' \s+' )[0 ] -eq ' ls' -and $_.Type -eq ' Aliased' }
221+ }
222+ }
223+
224+ It ' rm -fr matches rm -rf entry (flag reorder)' {
225+ InModuleScope PSCommandHelper {
226+ $line = ' rm -fr somedir'
227+ $lineFlags = [System.Collections.Generic.HashSet [char ]]::new()
228+ $lineParts = ($line -split ' \s+' ) | Select-Object - Skip 1
229+ foreach ($part in $lineParts ) {
230+ if ($part -match ' ^-([A-Za-z0-9]+)$' ) {
231+ foreach ($ch in $Matches [1 ].ToCharArray()) { [void ]$lineFlags.Add ($ch ) }
232+ }
233+ }
234+
235+ $bestMatch = $null
236+ $bestScore = -1
237+ foreach ($entry in $script :TestRmEntries ) {
238+ $entryFlags = [System.Collections.Generic.HashSet [char ]]::new()
239+ $entryParts = ($entry.Bash -split ' \s+' ) | Select-Object - Skip 1
240+ foreach ($part in $entryParts ) {
241+ if ($part -match ' ^-([A-Za-z0-9]+)$' ) {
242+ foreach ($ch in $Matches [1 ].ToCharArray()) { [void ]$entryFlags.Add ($ch ) }
243+ }
244+ }
245+ if ($entryFlags.Count -gt 0 -and $entryFlags.IsSubsetOf ($lineFlags )) {
246+ if ($entryFlags.Count -gt $bestScore ) {
247+ $bestScore = $entryFlags.Count
248+ $bestMatch = $entry
249+ }
250+ }
251+ }
252+
253+ $bestMatch | Should -Not - BeNull
254+ $bestMatch.Bash | Should - Be ' rm -rf'
255+ $bestMatch.PowerShell | Should - Be ' Remove-Item -Recurse -Force'
256+ }
257+ }
258+
259+ It ' rm -r -f matches rm -rf entry (separated flags)' {
260+ InModuleScope PSCommandHelper {
261+ $line = ' rm -r -f somedir'
262+ $lineFlags = [System.Collections.Generic.HashSet [char ]]::new()
263+ $lineParts = ($line -split ' \s+' ) | Select-Object - Skip 1
264+ foreach ($part in $lineParts ) {
265+ if ($part -match ' ^-([A-Za-z0-9]+)$' ) {
266+ foreach ($ch in $Matches [1 ].ToCharArray()) { [void ]$lineFlags.Add ($ch ) }
267+ }
268+ }
269+
270+ $bestMatch = $null
271+ $bestScore = -1
272+ foreach ($entry in $script :TestRmEntries ) {
273+ $entryFlags = [System.Collections.Generic.HashSet [char ]]::new()
274+ $entryParts = ($entry.Bash -split ' \s+' ) | Select-Object - Skip 1
275+ foreach ($part in $entryParts ) {
276+ if ($part -match ' ^-([A-Za-z0-9]+)$' ) {
277+ foreach ($ch in $Matches [1 ].ToCharArray()) { [void ]$entryFlags.Add ($ch ) }
278+ }
279+ }
280+ if ($entryFlags.Count -gt 0 -and $entryFlags.IsSubsetOf ($lineFlags )) {
281+ if ($entryFlags.Count -gt $bestScore ) {
282+ $bestScore = $entryFlags.Count
283+ $bestMatch = $entry
284+ }
285+ }
286+ }
287+
288+ $bestMatch | Should -Not - BeNull
289+ $bestMatch.Bash | Should - Be ' rm -rf'
290+ }
291+ }
292+
293+ It ' ls -al matches ls -la entry (flag reorder)' {
294+ InModuleScope PSCommandHelper {
295+ $line = ' ls -al'
296+ $lineFlags = [System.Collections.Generic.HashSet [char ]]::new()
297+ $lineParts = ($line -split ' \s+' ) | Select-Object - Skip 1
298+ foreach ($part in $lineParts ) {
299+ if ($part -match ' ^-([A-Za-z0-9]+)$' ) {
300+ foreach ($ch in $Matches [1 ].ToCharArray()) { [void ]$lineFlags.Add ($ch ) }
301+ }
302+ }
303+
304+ $bestMatch = $null
305+ $bestScore = -1
306+ foreach ($entry in $script :TestLsEntries ) {
307+ $entryFlags = [System.Collections.Generic.HashSet [char ]]::new()
308+ $entryParts = ($entry.Bash -split ' \s+' ) | Select-Object - Skip 1
309+ foreach ($part in $entryParts ) {
310+ if ($part -match ' ^-([A-Za-z0-9]+)$' ) {
311+ foreach ($ch in $Matches [1 ].ToCharArray()) { [void ]$entryFlags.Add ($ch ) }
312+ }
313+ }
314+ if ($entryFlags.Count -gt 0 -and $entryFlags.IsSubsetOf ($lineFlags )) {
315+ if ($entryFlags.Count -gt $bestScore ) {
316+ $bestScore = $entryFlags.Count
317+ $bestMatch = $entry
318+ }
319+ }
320+ }
321+
322+ $bestMatch | Should -Not - BeNull
323+ $bestMatch.Bash | Should - Be ' ls -la'
324+ }
325+ }
326+
327+ It ' rm -rf still matches exactly (no regression)' {
328+ InModuleScope PSCommandHelper {
329+ $line = ' rm -rf somedir'
330+ $lineFlags = [System.Collections.Generic.HashSet [char ]]::new()
331+ $lineParts = ($line -split ' \s+' ) | Select-Object - Skip 1
332+ foreach ($part in $lineParts ) {
333+ if ($part -match ' ^-([A-Za-z0-9]+)$' ) {
334+ foreach ($ch in $Matches [1 ].ToCharArray()) { [void ]$lineFlags.Add ($ch ) }
335+ }
336+ }
337+
338+ $bestMatch = $null
339+ $bestScore = -1
340+ foreach ($entry in $script :TestRmEntries ) {
341+ $entryFlags = [System.Collections.Generic.HashSet [char ]]::new()
342+ $entryParts = ($entry.Bash -split ' \s+' ) | Select-Object - Skip 1
343+ foreach ($part in $entryParts ) {
344+ if ($part -match ' ^-([A-Za-z0-9]+)$' ) {
345+ foreach ($ch in $Matches [1 ].ToCharArray()) { [void ]$entryFlags.Add ($ch ) }
346+ }
347+ }
348+ if ($entryFlags.Count -gt 0 -and $entryFlags.IsSubsetOf ($lineFlags )) {
349+ if ($entryFlags.Count -gt $bestScore ) {
350+ $bestScore = $entryFlags.Count
351+ $bestMatch = $entry
352+ }
353+ }
354+ }
355+
356+ $bestMatch | Should -Not - BeNull
357+ $bestMatch.Bash | Should - Be ' rm -rf'
358+ }
359+ }
360+ }
361+
153362Describe ' Enable/Disable-PSCommandHelper' {
154363 AfterEach {
155364 Disable-PSCommandHelper 6>&1 | Out-Null
0 commit comments