Skip to content

Commit 4aa3062

Browse files
committed
Move AliasVisitor to class file
And switch to HashSet[string] instead of Hashtable semver:breaking
1 parent 854df01 commit 4aa3062

3 files changed

Lines changed: 125 additions & 111 deletions

File tree

Source/Classes/AliasVisitor.ps1

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
using namespace System.Management.Automation.Language
2+
using namespace System.Collections.Generic
3+
4+
# This is used only to parse the parameters to New|Set|Remove-Alias
5+
class AliasParameterVisitor : AstVisitor {
6+
[string]$Parameter = $null
7+
[string]$Command = $null
8+
[string]$Name = $null
9+
[string]$Value = $null
10+
[string]$Scope = $null
11+
12+
# Parameter Names
13+
[AstVisitAction] VisitCommandParameter([CommandParameterAst]$ast) {
14+
$this.Parameter = $ast.ParameterName
15+
return [AstVisitAction]::Continue
16+
}
17+
18+
# Parameter Values
19+
[AstVisitAction] VisitStringConstantExpression([StringConstantExpressionAst]$ast) {
20+
# The FIRST command element is always the command name
21+
if (!$this.Command) {
22+
$this.Command = $ast.Value
23+
return [AstVisitAction]::Continue
24+
} else {
25+
# Nobody should use minimal parameters like -N for -Name ...
26+
# But if they do, our parser works anyway!
27+
switch -Wildcard ($this.Parameter) {
28+
"S*" {
29+
$this.Scope = $ast.Value
30+
}
31+
"N*" {
32+
$this.Name = $ast.Value
33+
}
34+
"Va*" {
35+
$this.Value = $ast.Value
36+
}
37+
"F*" {
38+
if ($ast.Value) {
39+
# Force parameter was passed as named parameter with a positional parameter after it which is alias name
40+
$this.Name = $ast.Value
41+
}
42+
}
43+
default {
44+
if (!$this.Parameter) {
45+
# For bare arguments, the order is Name, Value:
46+
if (!$this.Name) {
47+
$this.Name = $ast.Value
48+
} else {
49+
$this.Value = $ast.Value
50+
}
51+
}
52+
}
53+
}
54+
55+
$this.Parameter = $null
56+
57+
# If we have enough information, stop the visit
58+
# For -Scope global or Remove-Alias, we don't want to export these
59+
if ($this.Name -and $this.Command -eq "Remove-Alias") {
60+
$this.Command = "Remove-Alias"
61+
return [AstVisitAction]::StopVisit
62+
} elseif ($this.Name -and $this.Scope -eq "Global") {
63+
return [AstVisitAction]::StopVisit
64+
}
65+
return [AstVisitAction]::Continue
66+
}
67+
}
68+
69+
[AliasParameterVisitor] Clear() {
70+
$this.Command = $null
71+
$this.Parameter = $null
72+
$this.Name = $null
73+
$this.Value = $null
74+
$this.Scope = $null
75+
return $this
76+
}
77+
}
78+
79+
# This visits everything at the top level of the script
80+
class AliasVisitor : AstVisitor {
81+
[HashSet[String]]$Aliases = @()
82+
[AliasParameterVisitor]$Parameters = @{}
83+
84+
# The [Alias(...)] attribute on functions matters, but we can't export aliases that are defined inside a function
85+
[AstVisitAction] VisitFunctionDefinition([FunctionDefinitionAst]$ast) {
86+
@($ast.Body.ParamBlock.Attributes.Where{
87+
$_.TypeName.Name -eq "Alias"
88+
}.PositionalArguments.Value).ForEach{
89+
if ($_) {
90+
$this.Aliases.Add($_)
91+
}
92+
}
93+
94+
return [AstVisitAction]::SkipChildren
95+
}
96+
97+
# Top-level commands matter, but only if they're alias commands
98+
[AstVisitAction] VisitCommand([CommandAst]$ast) {
99+
if ($ast.CommandElements[0].Value -imatch "(New|Set|Remove)-Alias") {
100+
$ast.Visit($this.Parameters.Clear())
101+
102+
# We COULD just remove it (even if we didn't add it) ...
103+
if ($this.Parameters.Command -ieq "Remove-Alias") {
104+
# But Write-Verbose for logging purposes
105+
if ($this.Aliases.Contains($this.Parameters.Name)) {
106+
Write-Verbose -Message "Alias '$($this.Parameters.Name)' is removed by line $($ast.Extent.StartLineNumber): $($ast.Extent.Text)"
107+
$this.Aliases.Remove($this.Parameters.Name)
108+
}
109+
# We don't need to export global aliases, because they broke out already
110+
} elseif ($this.Parameters.Name -and $this.Parameters.Scope -ine 'Global') {
111+
$this.Aliases.Add($this.Parameters.Name)
112+
}
113+
}
114+
return [AstVisitAction]::SkipChildren
115+
}
116+
}

Source/Private/GetCommandAlias.ps1

Lines changed: 1 addition & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -1,113 +1,11 @@
1-
# This is used only to parse the parameters to New|Set|Remove-Alias
2-
class AliasParameterVisitor : System.Management.Automation.Language.AstVisitor {
3-
[string]$Parameter = $null
4-
[string]$Command = $null
5-
[string]$Name = $null
6-
[string]$Value = $null
7-
[string]$Scope = $null
8-
9-
# Parameter Names
10-
[System.Management.Automation.Language.AstVisitAction] VisitCommandParameter([System.Management.Automation.Language.CommandParameterAst]$ast) {
11-
$this.Parameter = $ast.ParameterName
12-
return [System.Management.Automation.Language.AstVisitAction]::Continue
13-
}
14-
15-
# Parameter Values
16-
[System.Management.Automation.Language.AstVisitAction] VisitStringConstantExpression([System.Management.Automation.Language.StringConstantExpressionAst]$ast) {
17-
# The FIRST command element is always the command name
18-
if (!$this.Command) {
19-
$this.Command = $ast.Value
20-
return [System.Management.Automation.Language.AstVisitAction]::Continue
21-
} else {
22-
switch ($this.Parameter) {
23-
"Scope" {
24-
$this.Scope = $ast.Value
25-
}
26-
"Name" {
27-
$this.Name = $ast.Value
28-
}
29-
"Value" {
30-
$this.Value = $ast.Value
31-
}
32-
"Force" {
33-
if ($ast.Value) {
34-
# Force parameter was passed as named parameter with a positional parameter after it which is alias name
35-
$this.Name = $ast.Value
36-
}
37-
}
38-
default {
39-
if (!$this.Parameter) {
40-
# For bare arguments, the order is Name, Value:
41-
if (!$this.Name) {
42-
$this.Name = $ast.Value
43-
} else {
44-
$this.Value = $ast.Value
45-
}
46-
}
47-
}
48-
}
49-
50-
$this.Parameter = $null
51-
52-
# If we have enough information, stop the visit
53-
# For -Scope global or Remove-Alias, we don't want to export these
54-
if ($this.Name -and $this.Command -eq "Remove-Alias") {
55-
$this.Command = "Remove-Alias"
56-
return [System.Management.Automation.Language.AstVisitAction]::StopVisit
57-
} elseif ($this.Name -and $this.Scope -eq "Global") {
58-
return [System.Management.Automation.Language.AstVisitAction]::StopVisit
59-
}
60-
return [System.Management.Automation.Language.AstVisitAction]::Continue
61-
}
62-
}
63-
64-
[AliasParameterVisitor] Clear() {
65-
$this.Command = $null
66-
$this.Parameter = $null
67-
$this.Name = $null
68-
$this.Value = $null
69-
$this.Scope = $null
70-
return $this
71-
}
72-
}
73-
74-
# This visits everything at the top level of the script
75-
class AliasVisitor : System.Management.Automation.Language.AstVisitor {
76-
[System.Collections.Hashtable]$Aliases = @{}
77-
[AliasParameterVisitor]$Parameters = @{}
78-
79-
# The [Alias(...)] attribute on functions matters, but we can't export aliases that are defined inside a function
80-
[System.Management.Automation.Language.AstVisitAction] VisitFunctionDefinition([System.Management.Automation.Language.FunctionDefinitionAst]$ast) {
81-
$this.Aliases[$ast.Name] = @($ast.Body.ParamBlock.Attributes.Where{ $_.TypeName.Name -eq "Alias" }.PositionalArguments.Value)
82-
return [System.Management.Automation.Language.AstVisitAction]::SkipChildren
83-
}
84-
85-
# Top-level commands matter, but only if they're alias commands
86-
[System.Management.Automation.Language.AstVisitAction] VisitCommand([System.Management.Automation.Language.CommandAst]$ast) {
87-
if ($ast.CommandElements[0].Value -imatch "(New|Set|Remove)-Alias") {
88-
$ast.Visit($this.Parameters.Clear())
89-
if ($this.Parameters.Command -ieq "Remove-Alias") {
90-
Write-Warning -Message "Found an alias '$($this.Parameters.Name)' that is removed using $($this.Parameters.Command), assuming the alias should not be exported."
91-
92-
$this.Aliases.Remove($this.Parameters.Name)
93-
} elseif ($this.Parameters.Scope -ine 'Global') {
94-
if ($this.Parameters.Name -notin $this.Aliases.Keys)
95-
{
96-
$this.Aliases[$this.Parameters.Name] = $this.Parameters.Name
97-
}
98-
}
99-
}
100-
return [System.Management.Automation.Language.AstVisitAction]::SkipChildren
101-
}
102-
}
1031

1042
function GetCommandAlias {
1053
<#
1064
.SYNOPSIS
1075
Parses one or more files for aliases and returns a list of alias names.
1086
#>
1097
[CmdletBinding()]
110-
[OutputType([System.Collections.Hashtable])]
8+
[OutputType([System.Collections.Generic.Hashset[string]])]
1119
param(
11210
# The AST to find aliases in
11311
[Parameter(Mandatory, ValueFromPipelineByPropertyName, ValueFromPipeline)]

Source/Public/Build-Module.ps1

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -213,20 +213,20 @@ function Build-Module {
213213
$ParseResult = ConvertToAst $RootModule
214214
$ParseResult | MoveUsingStatements -Encoding "$($ModuleInfo.Encoding)"
215215

216-
if (-not $ModuleInfo.IgnoreAlias) {
217-
$AliasesToExport = $ParseResult | GetCommandAlias
218-
}
219-
220216
# If there is a PublicFilter, update ExportedFunctions
221217
if ($ModuleInfo.PublicFilter) {
222218
# SilentlyContinue because there don't *HAVE* to be public functions
223-
if (($PublicFunctions = Get-ChildItem $ModuleInfo.PublicFilter -Recurse -ErrorAction SilentlyContinue | Where-Object BaseName -in $AllScripts.BaseName | Select-Object -ExpandProperty BaseName)) {
224-
Update-Metadata -Path $OutputManifest -PropertyName FunctionsToExport -Value ($PublicFunctions | Where-Object {$_ -notin $AliasesToExport.Values})
219+
if (($PublicFunctions = Get-ChildItem $ModuleInfo.PublicFilter -Recurse -ErrorAction SilentlyContinue |
220+
Where-Object BaseName -in $AllScripts.BaseName |
221+
Select-Object -ExpandProperty BaseName)) {
222+
223+
Update-Metadata -Path $OutputManifest -PropertyName FunctionsToExport -Value $PublicFunctions
225224
}
226225
}
227226

228-
if ($PublicFunctions -and -not $ModuleInfo.IgnoreAlias) {
229-
if (($AliasesToExport = $AliasesToExport[$PublicFunctions] | ForEach-Object { $_ } | Select-Object -Unique)) {
227+
# In order to support aliases to files, such as required by Invoke-Build, always export aliases
228+
if (-not $ModuleInfo.IgnoreAlias) {
229+
if (($AliasesToExport = $ParseResult | GetCommandAlias)) {
230230
Update-Metadata -Path $OutputManifest -PropertyName AliasesToExport -Value $AliasesToExport
231231
}
232232
}

0 commit comments

Comments
 (0)