From 7fe389305d011fec9038516260a6da65fdd70e51 Mon Sep 17 00:00:00 2001 From: Marius Storhaug Date: Sun, 2 Feb 2025 21:33:03 +0100 Subject: [PATCH] [Feature]: Introduce new AST command functions and update examples for consistency --- examples/General.ps1 | 12 ++-- src/functions/public/Core/Get-ASTCommand.ps1 | 25 ++++++++ ...et-FunctionAST.ps1 => Get-ASTFunction.ps1} | 0 .../{Get-ScriptAST.ps1 => Get-ASTScript.ps1} | 0 ...tionAlias.ps1 => Get-ASTFunctionAlias.ps1} | 16 +++-- ...nctionName.ps1 => Get-ASTFunctionName.ps1} | 0 ...nctionType.ps1 => Get-ASTFunctionType.ps1} | 0 ...LineComment.ps1 => Get-ASTLineComment.ps1} | 12 ++-- ...ptCommand.ps1 => Get-ASTScriptCommand.ps1} | 9 ++- tests/Module.Tests.ps1 | 58 ++++++++++--------- 10 files changed, 81 insertions(+), 51 deletions(-) create mode 100644 src/functions/public/Core/Get-ASTCommand.ps1 rename src/functions/public/Core/{Get-FunctionAST.ps1 => Get-ASTFunction.ps1} (100%) rename src/functions/public/Core/{Get-ScriptAST.ps1 => Get-ASTScript.ps1} (100%) rename src/functions/public/Functions/{Get-FunctionAlias.ps1 => Get-ASTFunctionAlias.ps1} (69%) rename src/functions/public/Functions/{Get-FunctionName.ps1 => Get-ASTFunctionName.ps1} (100%) rename src/functions/public/Functions/{Get-FunctionType.ps1 => Get-ASTFunctionType.ps1} (100%) rename src/functions/public/Lines/{Get-LineComment.ps1 => Get-ASTLineComment.ps1} (75%) rename src/functions/public/Scripts/{Get-ScriptCommand.ps1 => Get-ASTScriptCommand.ps1} (87%) diff --git a/examples/General.ps1 b/examples/General.ps1 index 097815c..97812de 100644 --- a/examples/General.ps1 +++ b/examples/General.ps1 @@ -1,16 +1,16 @@ # Gets the AST of a script. Can be any type of PowerShell script file. -Get-ScriptAST -Path $path +Get-ASTScript -Path $path # Gets the AST of a function(s) in a script. Can be any type of PowerShell script file. -Get-FunctionAST -Path $path +Get-ASTFunction -Path $path # Gets the type of all functions in a script file. Function or filter. -Get-FunctionType -Path $path +Get-ASTFunctionType -Path $path # Gets the name of all functions in a script file. -Get-FunctionName -Path $path +Get-ASTFunctionName -Path $path # Gets the alias of a function in a script, that uses Alias attribute. -Get-FunctionAlias -Path $path +Get-ASTFunctionAlias -Path $path -'Get-ChildItem -Path . # This is a comment' | Get-LineComment +'Get-ChildItem -Path . # This is a comment' | Get-ASTLineComment diff --git a/src/functions/public/Core/Get-ASTCommand.ps1 b/src/functions/public/Core/Get-ASTCommand.ps1 new file mode 100644 index 0000000..feacde3 --- /dev/null +++ b/src/functions/public/Core/Get-ASTCommand.ps1 @@ -0,0 +1,25 @@ +function Get-ASTCommand { + [CmdletBinding()] + param ( + # The name of the command to search for. Defaults to all commands ('*'). + [Parameter()] + [string] $Name = '*', + + # The path to the PowerShell script file to be parsed. + [Parameter(Mandatory)] + [ValidateScript({ Test-Path -Path $_ -PathType Leaf })] + [string] $Path + ) + + begin {} + + process { + # Parse the script file into an AST + $ast = Get-ASTScript -Path $Path + + # Extract function definitions + $ast.FindAll({ $args[0] -is [System.Management.Automation.Language.CommandAst] }, $true) | Where-Object { $_.Name -like $Name } + } + + end {} +} diff --git a/src/functions/public/Core/Get-FunctionAST.ps1 b/src/functions/public/Core/Get-ASTFunction.ps1 similarity index 100% rename from src/functions/public/Core/Get-FunctionAST.ps1 rename to src/functions/public/Core/Get-ASTFunction.ps1 diff --git a/src/functions/public/Core/Get-ScriptAST.ps1 b/src/functions/public/Core/Get-ASTScript.ps1 similarity index 100% rename from src/functions/public/Core/Get-ScriptAST.ps1 rename to src/functions/public/Core/Get-ASTScript.ps1 diff --git a/src/functions/public/Functions/Get-FunctionAlias.ps1 b/src/functions/public/Functions/Get-ASTFunctionAlias.ps1 similarity index 69% rename from src/functions/public/Functions/Get-FunctionAlias.ps1 rename to src/functions/public/Functions/Get-ASTFunctionAlias.ps1 index 3265c7e..88c453e 100644 --- a/src/functions/public/Functions/Get-FunctionAlias.ps1 +++ b/src/functions/public/Functions/Get-ASTFunctionAlias.ps1 @@ -1,4 +1,4 @@ -function Get-FunctionAlias { +function Get-ASTFunctionAlias { <# .SYNOPSIS Retrieves function aliases from a PowerShell script file. @@ -8,17 +8,17 @@ Returns a custom object containing function names and their corresponding aliases. .EXAMPLE - Get-FunctionAlias -Path "C:\Scripts\MyScript.ps1" + Get-ASTFunctionAlias -Path "C:\Scripts\MyScript.ps1" Retrieves all function aliases defined in the specified script file. .EXAMPLE - Get-FunctionAlias -Name "Get-Data" -Path "C:\Scripts\MyScript.ps1" + Get-ASTFunctionAlias -Name "Get-Data" -Path "C:\Scripts\MyScript.ps1" Retrieves the alias information for the function named "Get-Data" from the specified script file. .LINK - https://psmodule.io/AST/Functions/Functions/Get-FunctionAlias/ + https://psmodule.io/AST/Functions/Functions/Get-ASTFunctionAlias/ #> [CmdletBinding()] param ( @@ -38,8 +38,12 @@ # Process each function and extract aliases $functions | ForEach-Object { $funcName = $_.Name - $attributes = $_.FindAll({ $args[0] -is [System.Management.Automation.Language.AttributeAst] }, $true) - $aliasAttr = $attributes | Where-Object { $_ -is [System.Management.Automation.Language.AttributeAst] -and $_.TypeName.Name -eq 'Alias' } + $funcAttributes = $_.Body.FindAll({ $args[0] -is [System.Management.Automation.Language.AttributeAst] }, $true) + + # Filter only function-level alias attributes + $aliasAttr = $funcAttributes | Where-Object { + $_.TypeName.Name -eq 'Alias' -and $_.Parent -is [System.Management.Automation.Language.FunctionDefinitionAst] + } if ($aliasAttr) { $aliases = $aliasAttr.PositionalArguments | ForEach-Object { $_.ToString().Trim('"', "'") } diff --git a/src/functions/public/Functions/Get-FunctionName.ps1 b/src/functions/public/Functions/Get-ASTFunctionName.ps1 similarity index 100% rename from src/functions/public/Functions/Get-FunctionName.ps1 rename to src/functions/public/Functions/Get-ASTFunctionName.ps1 diff --git a/src/functions/public/Functions/Get-FunctionType.ps1 b/src/functions/public/Functions/Get-ASTFunctionType.ps1 similarity index 100% rename from src/functions/public/Functions/Get-FunctionType.ps1 rename to src/functions/public/Functions/Get-ASTFunctionType.ps1 diff --git a/src/functions/public/Lines/Get-LineComment.ps1 b/src/functions/public/Lines/Get-ASTLineComment.ps1 similarity index 75% rename from src/functions/public/Lines/Get-LineComment.ps1 rename to src/functions/public/Lines/Get-ASTLineComment.ps1 index 4dc64ed..3202e74 100644 --- a/src/functions/public/Lines/Get-LineComment.ps1 +++ b/src/functions/public/Lines/Get-ASTLineComment.ps1 @@ -1,4 +1,4 @@ -filter Get-LineComment { +filter Get-ASTLineComment { <# .SYNOPSIS Extracts the inline comment from a single line of PowerShell code. @@ -8,23 +8,23 @@ If an inline comment exists, the function returns the comment text; otherwise, it returns nothing. .EXAMPLE - 'Get-Process # This retrieves all processes' | Get-LineComment + 'Get-Process # This retrieves all processes' | Get-ASTLineComment Returns: '# This retrieves all processes' .EXAMPLE - 'Write-Host "Hello World"' | Get-LineComment + 'Write-Host "Hello World"' | Get-ASTLineComment Returns: $null (no comment found) .LINK - https://psmodule.io/AST/Functions/Lines/Get-LineComment/ + https://psmodule.io/AST/Functions/Lines/Get-ASTLineComment/ #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute( 'PSUseShouldProcessForStateChangingFunctions', '', Justification = 'Does not change state' )] - [OutputType([string])] + [OutputType([System.Management.Automation.Language.Token[]])] [CmdletBinding()] param ( # Input line of PowerShell code from which to extract the comment. @@ -40,5 +40,5 @@ $null = [System.Management.Automation.Language.Parser]::ParseInput($Line, [ref]$tokens, [ref]$null) # Find comment token(s) in the line. - ($tokens | Where-Object { $_.Kind -eq 'Comment' }).Extent.Text + ($tokens | Where-Object { $_.Kind -eq 'Comment' }) } diff --git a/src/functions/public/Scripts/Get-ScriptCommand.ps1 b/src/functions/public/Scripts/Get-ASTScriptCommand.ps1 similarity index 87% rename from src/functions/public/Scripts/Get-ScriptCommand.ps1 rename to src/functions/public/Scripts/Get-ASTScriptCommand.ps1 index 6c4c080..f0df259 100644 --- a/src/functions/public/Scripts/Get-ScriptCommand.ps1 +++ b/src/functions/public/Scripts/Get-ASTScriptCommand.ps1 @@ -1,4 +1,4 @@ -function Get-ScriptCommand { +function Get-ASTScriptCommand { <# .SYNOPSIS Retrieves the commands used within a specified PowerShell script. @@ -9,19 +9,18 @@ Returns details such as command name, position, and file reference. .EXAMPLE - Get-ScriptCommand -Path "C:\Scripts\example.ps1" + Get-ASTScriptCommand -Path "C:\Scripts\example.ps1" Extracts and lists all commands found in the specified PowerShell script. .EXAMPLE - Get-ScriptCommand -Path "C:\Scripts\example.ps1" -IncludeCallOperators + Get-ASTScriptCommand -Path "C:\Scripts\example.ps1" -IncludeCallOperators Extracts all commands, including those executed with call operators (& and .). .LINK - https://psmodule.io/AST/Functions/Scripts/Get-ScriptCommand/ + https://psmodule.io/AST/Functions/Scripts/Get-ASTScriptCommand/ #> - [Alias('Get-ScriptCommands')] [CmdletBinding()] param ( # The path to the PowerShell script file to be parsed. diff --git a/tests/Module.Tests.ps1 b/tests/Module.Tests.ps1 index 00a6d2b..e7cb212 100644 --- a/tests/Module.Tests.ps1 +++ b/tests/Module.Tests.ps1 @@ -1,16 +1,18 @@ -Describe 'Core' { +#Requires -Modules @{ ModuleName = 'Pester'; RequiredVersion = '5.7.1' } + +Describe 'Core' { Context "Function: 'Get-ScriptAST'" { It 'Get-ScriptAST gets the script AST' { $path = Join-Path $PSScriptRoot 'src\Test-Function.ps1' - $ast = Get-ScriptAST -Path $path + $ast = Get-ASTScript -Path $path $ast | Should -Not -BeNullOrEmpty $ast | Should -BeOfType [System.Management.Automation.Language.ScriptBlockAst] } } - Context "Function: 'Get-FunctionAST'" { - It 'Get-FunctionAST gets the function AST' { + Context "Function: 'Get-ASTFunction'" { + It 'Get-ASTFunction gets the function AST' { $path = Join-Path $PSScriptRoot 'src\Test-Function.ps1' - $ast = Get-FunctionAST -Path $path + $ast = Get-ASTFunction -Path $path $ast | Should -Not -BeNullOrEmpty $ast | Should -BeOfType [System.Management.Automation.Language.FunctionDefinitionAst] } @@ -18,24 +20,24 @@ } Describe 'Functions' { - Context "Function: 'Get-FunctionType'" { - It 'Get-FunctionAlias gets the function alias' { + Context "Function: 'Get-ASTFunctionType'" { + It 'Get-ASTFunctionAlias gets the function alias' { $path = Join-Path $PSScriptRoot 'src\Test-Function.ps1' - $functionType = Get-FunctionType -Path $path + $functionType = Get-ASTFunctionType -Path $path $functionType.Type | Should -Be 'Function' } } - Context "Function: 'Get-FunctionName'" { - It 'Get-FunctionName gets the function name' { + Context "Function: 'Get-ASTFunctionName'" { + It 'Get-ASTFunctionName gets the function name' { $path = Join-Path $PSScriptRoot 'src\Test-Function.ps1' - $functionName = Get-FunctionName -Path $path + $functionName = Get-ASTFunctionName -Path $path $functionName | Should -Be 'Test-Function' } } - Context "Function: 'Get-FunctionAlias'" { - It 'Get-FunctionAlias gets the function alias' { + Context "Function: 'Get-ASTFunctionAlias'" { + It 'Get-ASTFunctionAlias gets the function alias' { $path = Join-Path $PSScriptRoot 'src\Test-Function.ps1' - $functionAlias = Get-FunctionAlias -Path $path + $functionAlias = Get-ASTFunctionAlias -Path $path $functionAlias.Alias | Should -Contain 'Test' $functionAlias.Alias | Should -Contain 'TestFunc' $functionAlias.Alias | Should -Contain 'Test-Func' @@ -44,34 +46,34 @@ Describe 'Functions' { } Describe 'Line' { - Context 'Function: Get-LineComment' { - It 'Get-LineComment gets the line comment' { + Context 'Function: Get-ASTLineComment' { + It 'Get-ASTLineComment gets the line comment' { $line = '# This is a comment' - $line = Get-LineComment -Line $line + $line = Get-ASTLineComment -Line $line $line | Should -Be '# This is a comment' } - It 'Get-LineComment gets the line comment without leading whitespace' { + It 'Get-ASTLineComment gets the line comment without leading whitespace' { $line = ' # This is a comment' - $line = Get-LineComment -Line $line + $line = Get-ASTLineComment -Line $line $line | Should -Be '# This is a comment' } - It 'Get-LineComment gets the line comment but not the command' { + It 'Get-ASTLineComment gets the line comment but not the command' { $line = ' Get-Command # This is a comment ' - $line = Get-LineComment -Line $line + $line = Get-ASTLineComment -Line $line $line | Should -Be '# This is a comment ' } - It 'Get-LineComment returns nothing when no comment is present' { + It 'Get-ASTLineComment returns nothing when no comment is present' { $line = 'Get-Command' - $line | Get-LineComment | Should -BeNullOrEmpty + $line | Get-ASTLineComment | Should -BeNullOrEmpty } } } Describe 'Scripts' { - Context "Function: 'Get-ScriptCommands'" { - It 'Get-ScriptCommands gets the script commands' { + Context "Function: 'Get-ASTScriptCommands'" { + It 'Get-ASTScriptCommands gets the script commands' { $path = Join-Path $PSScriptRoot 'src\Test-Function.ps1' - $commands = Get-ScriptCommand -Path $path + $commands = Get-ASTScriptCommand -Path $path $commands | Should -Not -BeNullOrEmpty $commands | Should -BeOfType [pscustomobject] $commands.Name | Should -Contain 'ForEach-Object' @@ -81,9 +83,9 @@ Describe 'Scripts' { $commands.Name | Should -Not -Contain '.' $commands.Name | Should -Not -Contain '&' } - It 'Get-ScriptCommands gets the script commands with call operators' { + It 'Get-ASTScriptCommands gets the script commands with call operators' { $path = Join-Path $PSScriptRoot 'src\Test-Function.ps1' - $commands = Get-ScriptCommand -Path $path -IncludeCallOperators + $commands = Get-ASTScriptCommand -Path $path -IncludeCallOperators $commands | Should -Not -BeNullOrEmpty $commands | Should -BeOfType [pscustomobject] $commands.Name | Should -Contain 'ForEach-Object'