Skip to content

Commit

Permalink
(#208) Improve UX of Crescendo cmdlets
Browse files Browse the repository at this point in the history
This commit improves the author experience when
accelerating a native command.

This commit exposes all class properties as function
parameters. Where appropriate an argumentcompleter
attribute has been introduced to further enhance
the authoring experience when working with the
Microsoft.PowerShell.Crescendo module.
  • Loading branch information
steviecoaster committed Apr 17, 2024
1 parent 08a8ac3 commit e4eee64
Showing 1 changed file with 235 additions and 10 deletions.
245 changes: 235 additions & 10 deletions Microsoft.PowerShell.Crescendo/src/Microsoft.PowerShell.Crescendo.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -647,18 +647,137 @@ function Test-Handler {
function New-ParameterInfo {
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions","")]
param (
[Parameter(Position=0,Mandatory=$true)][string]$Name,
[Parameter(Position=1,Mandatory=$true)][AllowEmptyString()][string]$OriginalName
[Parameter(Position=0,Mandatory=$true)]
[string]
$Name,

[Parameter(Position=1,Mandatory=$true)]
[AllowEmptyString()]
[string]
$OriginalName,

[Parameter()]
[string]
$OriginalText,

[Parameter()]
[string]
$Description,

[Parameter()]
[string]
$DefaultValue,

# some parameters are -param or +param which can be represented with a switch parameter
# so we need way to provide for this
[Parameter()]
[string]
$DefaultMissingValue,

# this is in case that the parameters apply before the OriginalCommandElements
[Parameter()]
[bool]
$ApplyToExecutable,

# when true, we don't pass this parameter to the native application at all
[Parameter()]
[bool]
$ExcludeAsArgument,

# PSType
[Parameter()]
[string]
$ParameterType = 'object',

[Parameter()]
[string[]]
$AdditionalParameterAttributes,

[Parameter()]
[bool]
$Mandatory,

[Parameter()]
[string[]]
$ParameterSetName,

[Parameter()]
[string[]]
$Aliases,

[Parameter()]
[int]
$Position = [int]::MaxValue,

[Parameter()]
[int]
$OriginalPosition,

[Parameter()]
[bool]
$ValueFromPipeline,

[Parameter()]
[bool]
$ValueFromPipelineByPropertyName,

[Parameter()][bool]
$ValueFromRemainingArguments,

# this means that we need to construct the parameter as "foo=bar"
[Parameter()]
[bool]
$NoGap,

# This is a scriptblock, file or function which will transform the value(s) of the parameter
# If the value needs to be transformed, this is the scriptblock to do it
[Parameter()]
[string]
$ArgumentTransform,

# this can be inline, file, or function
# the default is inline, but we will follow the same logic as for output handlers
# if 'function' we will inspect the current environment for the function and embed it in the module
# if 'file' we will hunt for the file in the current environment and copy it to the module location
# the value as a single object will be passed as an argument to the scriptblock/file/function
[Parameter()]
[string]
$ArgumentTransformType
)
[ParameterInfo]::new($Name, $OriginalName)
$pi = [ParameterInfo]::new($Name,$OriginalName)

$PSBoundParameters.GetEnumerator() |
ForEach-Object {
$pi.$($PSItem.Key) = $PSItem.Value
}

$pi
}

function New-UsageInfo {
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions","")]
param (
[Parameter(Position=0,Mandatory=$true)][string]$usage
[Parameter(Position=0,Mandatory=$true)]
[string]
$Synopsis,

[Parameter()]
[Switch]
$SupportsFlags,

[Parameter()]
[Switch]
$HasOptions

)
[UsageInfo]::new($usage)
$ui = [UsageInfo]::new($usage)

$PSBoundParameters.GetEnumerator() | ForEach-Object {
$ui.$($PSItem.Key) = $PSItem.Value
}

$ui

}

function New-ExampleInfo {
Expand All @@ -673,20 +792,126 @@ function New-ExampleInfo {

function New-OutputHandler {
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions","")]
param ( )
[OutputHandler]::new()
param (
[Parameter()]
[string]
$ParameterSetName,

# This is a scriptblock which does the conversion to an object
[Parameter()]
[string]
$Handler,

# Inline, Function, Script, or ByPass
[Parameter()]
[string]
$HandlerType,

# this indicates whether the output should be streamed to the handler
[Parameter()]
[bool]
$StreamOutput

)

$oh = [OutputHandler]::new() # I O!
$PSBoundParameters.GetEnumerator() |
ForEach-Object {
$oh.$($psitem.Key) = $PSItem.Value
}
$oh

}

function New-CrescendoCommand {
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions","")]
param (
[Parameter(Position=0,Mandatory=$true)][string]$Verb,
[Parameter(Position=1,Mandatory=$true)][string]$Noun,
[Parameter(Position=2)][string]$OriginalName
[Parameter(Position = 0)]
[ArgumentCompleter( {
param ( $commandName,
$parameterName,
$wordToComplete,
$commandAst,
$fakeBoundParameters )
if ($WordToComplete) {
(Get-Verb).Verb | Where-Object { $_ -match "^$WordToComplete"}
}

else {
(Get-Verb).Verb
}
} )]
[String]
$Verb,

[Parameter(Position = 1)]
[string]
$Noun,

[Parameter(Position=2)]
[string]
$OriginalName,

[Parameter(Position=3)]
[string]
$Description,

[Parameter()]
[string[]]
$Aliases,

[Parameter()]
[string] $DefaultParameterSetName,

[Parameter()]
[bool]
$SupportsShouldProcess,

[Parameter()]
[string]
$ConfirmImpact,

[Parameter()]
[bool]
$SupportsTransactions,

[Parameter()]
[bool]
$NoInvocation,
# certain scenarios want to use the generated code as a front end. When true, the generated code will return the arguments only.
[Parameter()]
[UsageInfo]
$Usage,

[Parameter()]
[List[ParameterInfo]]
$Parameters,

[Parameter()]
[List[ExampleInfo]]
$Examples,

[Parameter()]
[string]
$OriginalText,

[Parameter()]
[string[]]
$HelpLinks,

[Parameter()]
[OutputHandler[]]
$OutputHandlers



)
$cmd = [Command]::new($Verb, $Noun)
$cmd.OriginalName = $OriginalName
$PSBoundParameters.GetEnumerator() |
ForEach-Object {
$cmd.$($psitem.Key) = $PSItem.Value
}
$cmd
}

Expand Down

0 comments on commit e4eee64

Please sign in to comment.