Skip to content

Commit e4eee64

Browse files
committed
(PowerShell#208) Improve UX of Crescendo cmdlets
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.
1 parent 08a8ac3 commit e4eee64

File tree

1 file changed

+235
-10
lines changed

1 file changed

+235
-10
lines changed

Microsoft.PowerShell.Crescendo/src/Microsoft.PowerShell.Crescendo.psm1

+235-10
Original file line numberDiff line numberDiff line change
@@ -647,18 +647,137 @@ function Test-Handler {
647647
function New-ParameterInfo {
648648
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions","")]
649649
param (
650-
[Parameter(Position=0,Mandatory=$true)][string]$Name,
651-
[Parameter(Position=1,Mandatory=$true)][AllowEmptyString()][string]$OriginalName
650+
[Parameter(Position=0,Mandatory=$true)]
651+
[string]
652+
$Name,
653+
654+
[Parameter(Position=1,Mandatory=$true)]
655+
[AllowEmptyString()]
656+
[string]
657+
$OriginalName,
658+
659+
[Parameter()]
660+
[string]
661+
$OriginalText,
662+
663+
[Parameter()]
664+
[string]
665+
$Description,
666+
667+
[Parameter()]
668+
[string]
669+
$DefaultValue,
670+
671+
# some parameters are -param or +param which can be represented with a switch parameter
672+
# so we need way to provide for this
673+
[Parameter()]
674+
[string]
675+
$DefaultMissingValue,
676+
677+
# this is in case that the parameters apply before the OriginalCommandElements
678+
[Parameter()]
679+
[bool]
680+
$ApplyToExecutable,
681+
682+
# when true, we don't pass this parameter to the native application at all
683+
[Parameter()]
684+
[bool]
685+
$ExcludeAsArgument,
686+
687+
# PSType
688+
[Parameter()]
689+
[string]
690+
$ParameterType = 'object',
691+
692+
[Parameter()]
693+
[string[]]
694+
$AdditionalParameterAttributes,
695+
696+
[Parameter()]
697+
[bool]
698+
$Mandatory,
699+
700+
[Parameter()]
701+
[string[]]
702+
$ParameterSetName,
703+
704+
[Parameter()]
705+
[string[]]
706+
$Aliases,
707+
708+
[Parameter()]
709+
[int]
710+
$Position = [int]::MaxValue,
711+
712+
[Parameter()]
713+
[int]
714+
$OriginalPosition,
715+
716+
[Parameter()]
717+
[bool]
718+
$ValueFromPipeline,
719+
720+
[Parameter()]
721+
[bool]
722+
$ValueFromPipelineByPropertyName,
723+
724+
[Parameter()][bool]
725+
$ValueFromRemainingArguments,
726+
727+
# this means that we need to construct the parameter as "foo=bar"
728+
[Parameter()]
729+
[bool]
730+
$NoGap,
731+
732+
# This is a scriptblock, file or function which will transform the value(s) of the parameter
733+
# If the value needs to be transformed, this is the scriptblock to do it
734+
[Parameter()]
735+
[string]
736+
$ArgumentTransform,
737+
738+
# this can be inline, file, or function
739+
# the default is inline, but we will follow the same logic as for output handlers
740+
# if 'function' we will inspect the current environment for the function and embed it in the module
741+
# if 'file' we will hunt for the file in the current environment and copy it to the module location
742+
# the value as a single object will be passed as an argument to the scriptblock/file/function
743+
[Parameter()]
744+
[string]
745+
$ArgumentTransformType
652746
)
653-
[ParameterInfo]::new($Name, $OriginalName)
747+
$pi = [ParameterInfo]::new($Name,$OriginalName)
748+
749+
$PSBoundParameters.GetEnumerator() |
750+
ForEach-Object {
751+
$pi.$($PSItem.Key) = $PSItem.Value
752+
}
753+
754+
$pi
654755
}
655756

656757
function New-UsageInfo {
657758
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions","")]
658759
param (
659-
[Parameter(Position=0,Mandatory=$true)][string]$usage
760+
[Parameter(Position=0,Mandatory=$true)]
761+
[string]
762+
$Synopsis,
763+
764+
[Parameter()]
765+
[Switch]
766+
$SupportsFlags,
767+
768+
[Parameter()]
769+
[Switch]
770+
$HasOptions
771+
660772
)
661-
[UsageInfo]::new($usage)
773+
$ui = [UsageInfo]::new($usage)
774+
775+
$PSBoundParameters.GetEnumerator() | ForEach-Object {
776+
$ui.$($PSItem.Key) = $PSItem.Value
777+
}
778+
779+
$ui
780+
662781
}
663782

664783
function New-ExampleInfo {
@@ -673,20 +792,126 @@ function New-ExampleInfo {
673792

674793
function New-OutputHandler {
675794
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions","")]
676-
param ( )
677-
[OutputHandler]::new()
795+
param (
796+
[Parameter()]
797+
[string]
798+
$ParameterSetName,
799+
800+
# This is a scriptblock which does the conversion to an object
801+
[Parameter()]
802+
[string]
803+
$Handler,
804+
805+
# Inline, Function, Script, or ByPass
806+
[Parameter()]
807+
[string]
808+
$HandlerType,
809+
810+
# this indicates whether the output should be streamed to the handler
811+
[Parameter()]
812+
[bool]
813+
$StreamOutput
814+
815+
)
816+
817+
$oh = [OutputHandler]::new() # I O!
818+
$PSBoundParameters.GetEnumerator() |
819+
ForEach-Object {
820+
$oh.$($psitem.Key) = $PSItem.Value
821+
}
822+
$oh
678823

679824
}
680825

681826
function New-CrescendoCommand {
682827
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions","")]
683828
param (
684-
[Parameter(Position=0,Mandatory=$true)][string]$Verb,
685-
[Parameter(Position=1,Mandatory=$true)][string]$Noun,
686-
[Parameter(Position=2)][string]$OriginalName
829+
[Parameter(Position = 0)]
830+
[ArgumentCompleter( {
831+
param ( $commandName,
832+
$parameterName,
833+
$wordToComplete,
834+
$commandAst,
835+
$fakeBoundParameters )
836+
if ($WordToComplete) {
837+
(Get-Verb).Verb | Where-Object { $_ -match "^$WordToComplete"}
838+
}
839+
840+
else {
841+
(Get-Verb).Verb
842+
}
843+
} )]
844+
[String]
845+
$Verb,
846+
847+
[Parameter(Position = 1)]
848+
[string]
849+
$Noun,
850+
851+
[Parameter(Position=2)]
852+
[string]
853+
$OriginalName,
854+
855+
[Parameter(Position=3)]
856+
[string]
857+
$Description,
858+
859+
[Parameter()]
860+
[string[]]
861+
$Aliases,
862+
863+
[Parameter()]
864+
[string] $DefaultParameterSetName,
865+
866+
[Parameter()]
867+
[bool]
868+
$SupportsShouldProcess,
869+
870+
[Parameter()]
871+
[string]
872+
$ConfirmImpact,
873+
874+
[Parameter()]
875+
[bool]
876+
$SupportsTransactions,
877+
878+
[Parameter()]
879+
[bool]
880+
$NoInvocation,
881+
# certain scenarios want to use the generated code as a front end. When true, the generated code will return the arguments only.
882+
[Parameter()]
883+
[UsageInfo]
884+
$Usage,
885+
886+
[Parameter()]
887+
[List[ParameterInfo]]
888+
$Parameters,
889+
890+
[Parameter()]
891+
[List[ExampleInfo]]
892+
$Examples,
893+
894+
[Parameter()]
895+
[string]
896+
$OriginalText,
897+
898+
[Parameter()]
899+
[string[]]
900+
$HelpLinks,
901+
902+
[Parameter()]
903+
[OutputHandler[]]
904+
$OutputHandlers
905+
906+
907+
687908
)
688909
$cmd = [Command]::new($Verb, $Noun)
689910
$cmd.OriginalName = $OriginalName
911+
$PSBoundParameters.GetEnumerator() |
912+
ForEach-Object {
913+
$cmd.$($psitem.Key) = $PSItem.Value
914+
}
690915
$cmd
691916
}
692917

0 commit comments

Comments
 (0)