Skip to content

Commit c0d6230

Browse files
Merge pull request #492 from StartAutomating/PipeScript-Automatic
PipeScript 0.2.6
2 parents 27c1822 + d57b327 commit c0d6230

File tree

197 files changed

+15947
-3598
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

197 files changed

+15947
-3598
lines changed

.github/FUNDING.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
github: [StartAutomating]

.github/workflows/OnIssue.yml renamed to .github/workflows/GitPub.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11

2-
name: OnIssueChanged
2+
name: GitPub
33
on:
4-
issues:
54
workflow_dispatch:
65
jobs:
76
RunGitPub:

.github/workflows/TestAndPublish.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -596,5 +596,4 @@ jobs:
596596
uses: StartAutomating/EZOut@master
597597
- name: UseHelpOut
598598
uses: StartAutomating/HelpOut@master
599-
env:
600-
NoCoverage: true
599+
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<#
2+
.SYNOPSIS
3+
Ensures Examples Work
4+
.DESCRIPTION
5+
Ensures Examples work by turning each example into a test.
6+
7+
Including a comment followed by 'should' will turn specific lines of the test into Pester should statements.
8+
#>
9+
param(
10+
$ModuleName = 'PipeScript'
11+
)
12+
13+
$moduleInfo = Get-Module $ModuleName
14+
$commandsInModule = Get-Command -Module $moduleName
15+
16+
$commandsWithExamples = $commandsInModule | Where-Object { $_.Examples }
17+
18+
$examplePattern = [Regex]::new('(?<ws>[\s\r\n]{0,})\#\s(?<P>.+?(?=\z|Should))?Should\s(?<C>.+?)$', 'IgnoreCase,IgnorePatternWhitespace', '00:00:05')
19+
20+
$testsDirectory = $moduleInfo | Split-Path | Join-Path -ChildPath Tests | Join-Path -ChildPath "Examples"
21+
22+
if (-not (Test-Path $testsDirectory)) {
23+
$null = New-Item -ItemType Directory -Path $testsDirectory
24+
}
25+
26+
foreach ($commandShouldWork in $commandsWithExamples) {
27+
$exampleCounter = 0
28+
$exampleFileContent =
29+
@(
30+
''
31+
"describe '$($commandShouldWork)' {"
32+
foreach ($commandExample in $commandShouldWork.Examples) {
33+
$exampleCounter++
34+
try {
35+
" it '$commandShouldWork Example $($exampleCounter)' {"
36+
37+
$examplePattern.Replace($commandExample, ' | ${P} Should ${C}')
38+
" }"
39+
} catch {
40+
$ex = $_
41+
# If for whatever reason the regex threw an exception, don't make a test out of this example.
42+
}
43+
}
44+
"}"
45+
'') -join [Environment]::newLine
46+
47+
$testFilePath = Join-Path $testsDirectory "$CommandShouldWork.examples.tests.ps1"
48+
$exampleFileContent | Set-Content $testFilePath
49+
Get-Item $testFilePath
50+
}
Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
1-
#requires -Module PSDevOps
1+
#requires -Module PSDevOps,GitPub
22
Import-BuildStep -ModuleName PipeScript
33
Push-Location ($PSScriptRoot | Split-Path)
4-
New-GitHubWorkflow -Name "Analyze, Test, Tag, and Publish" -On Push, PullRequest, Demand -Job PowerShellStaticAnalysis, TestPowerShellOnLinux, TagReleaseAndPublish, BuildPipeScript -Environment @{
5-
NoCoverage = $true
6-
} -OutputPath .\.github\workflows\TestAndPublish.yml
4+
New-GitHubWorkflow -Name "Analyze, Test, Tag, and Publish" -On Push,
5+
PullRequest,
6+
Demand -Job PowerShellStaticAnalysis,
7+
TestPowerShellOnLinux,
8+
TagReleaseAndPublish,
9+
BuildPipeScript -OutputPath .\.github\workflows\TestAndPublish.yml
10+
11+
New-GitHubWorkflow -On Demand -Job RunGitPub -Name GitPub -OutputPath .\.github\workflows\GitPub.yml
12+
713
Pop-Location

Build/PipeScript.Piecemeal.ps1

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,5 @@ Install-Piecemeal -ExtensionNoun 'Transpiler' -ExtensionPattern '\.psx\.ps1$','^
1010
Join-Path $commandsPath Get-Transpiler.ps1
1111
)
1212

13-
# So is Get-PipeScript
14-
Install-Piecemeal -ExtensionNoun 'PipeScript' -ExtensionPattern '\.psx\.ps1{0,1}$','\.ps1{0,1}\.(?<ext>[^.]+$)','\.ps1{0,1}$','^PipeScript.' -ExtensionTypeName 'PipeScript' -OutputPath (
15-
Join-Path $commandsPath Get-PipeScript.ps1
16-
)
17-
1813
# Pop back to wherever we were
1914
Pop-Location

CHANGELOG.md

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,80 @@
1+
## PipeScript 0.2.6:
2+
3+
* PipeScript can now be sponsored! (please show your support) (#488)
4+
5+
* PipeScript now has several formalized command types (#452)
6+
* Aspects
7+
* DynamicParameters (#462)
8+
* ModuleExtensionType (#460)
9+
* ModuleExtensionPattern (#460)
10+
* ModuleExtensionCommand (#460)
11+
* Automatic Variables (Fixes #426)
12+
* $MySelf
13+
* $MyParameters
14+
* $MyCallstack
15+
* $MyCaller
16+
* $MyCommandAst (#434)
17+
* $IsPipedTo (#430)
18+
* $IsPipedFrom (#431)
19+
* PostProcessing/Optimization now applies to Functions (#432)
20+
* Partial functions are now a PostProcessor (#449)
21+
* Protocol Functions
22+
* Made HTTP, UDP, and JSON Schema Protocols into functions (#474)
23+
* Added OpenAPI Protocol (#457)
24+
* Core Command Improvements
25+
* Get-PipeScript is now built with PipeScript (#463)
26+
* Export-PipeScript
27+
* Is _much_ more transparent in GitHub Workflow (#438)
28+
* Now lists all files built, time to build each, transpilers used, and PipeScript factor.
29+
* Auto Installs simple #requires in build files (#491)
30+
* Update-PipeScript uses AST Based Offsets (#439)
31+
* New-PipeScript
32+
* Making Description/Synopis ValueFromPipelineByPropertyName (#453)
33+
* Adding -InputObject parameter.
34+
* Making -Parameter _much_ more open-ended (#454)
35+
* Improving Reflection Support (#467)
36+
* Allowing -Parameter as `[CommandInfo]`/`[CommandMetaData]` (#477)
37+
* Supporting DefaultValue/ValidValue (Fixes #473)
38+
* Adding -Verb/-Noun (#468)
39+
* Invoke-PipeScript
40+
* Improving Positional Attribute Parameters (Fixes #70)
41+
* Clarifying 'Transpiler Not Found' Messages (#484)
42+
43+
* Sentence Parsing Support
44+
* Improving Mutliword alias support (#444)
45+
* Adding Clause.ParameterValues (#445)
46+
* Allowing N words to be skipped (#479)
47+
48+
* 'All' Improvements
49+
* Expanding Syntax for 'All' (#436)
50+
* Compacting generating code (#440)
51+
* Adding Greater Than / Less Than aliases (#446)
52+
* Enabling 'should' (#448)
53+
* 'all applications in $path' (#475)
54+
55+
* New Transpilers:
56+
* ValidValues (#451)
57+
* Adding WhereMethod (#465)
58+
* Adding ArrowOperator/ Lambdas ! (#464)
59+
60+
* Extended Type Improvements
61+
* VariableExpressionAst.GetVariableType - Enabling InvokeMemberExpression (#490)
62+
* CommandInfo.BlockComments - Resolving aliases (#487)
63+
* CommandInfo.GetHelpField - Skipping additional script blocks (Fixes #486)
64+
65+
* Minor Fixes:
66+
* Requires is now Quieter (#433)
67+
* Appending Unmapped Locations to Alias Namespace (Fixes #427)
68+
* Fixing Examples in New-PipeScript (thanks @ninmonkey !)
69+
* Namespaced Alias/Function - Not Transpiling if command found (#455)
70+
* Automatically Testing Examples (greatly expanded test coverage) (#461)
71+
* Templates now report errors more accurately (#489)
72+
* Inherit - Fixing Abstract/Dynamic Inheritance (#480)
73+
* Include - Allowing Including URLs (#481)
74+
* Partial Functions will not join their headers (#483)
75+
76+
---
77+
178
## PipeScript 0.2.5:
279

380
* Added Support for Aspects (#401)
Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
Aspect function DynamicParameter {
2+
<#
3+
.SYNOPSIS
4+
Dynamic Parameter Aspect
5+
.DESCRIPTION
6+
The Dynamic Parameter Aspect is used to add dynamic parameters, well, dynamically.
7+
8+
It can create dynamic parameters from one or more input objects or scripts.
9+
.EXAMPLE
10+
Get-Command Get-Command |
11+
Aspect.DynamicParameter
12+
.EXAMPLE
13+
Get-Command Get-Process |
14+
Aspect.DynamicParameter -IncludeParameter Name # Select -Expand Keys | Should -Be Name
15+
#>
16+
[Alias('Aspect.DynamicParameters')]
17+
param(
18+
# The InputObject.
19+
# This can be anything, but will be ignored unless it is a `[ScriptBlock]` or `[Management.Automation.CommandInfo]`.
20+
[vfp()]
21+
$InputObject,
22+
23+
# The name of the parameter set the dynamic parameters will be placed into.
24+
[string]
25+
$ParameterSetName,
26+
27+
# The positional offset. If this is provided, all positional parameters will be shifted by this number.
28+
# For example, if -PositionOffset is 1, the first parameter would become the second parameter (and so on)
29+
[int]
30+
$PositionOffset,
31+
32+
# If set, will make all dynamic parameters non-mandatory.
33+
[switch]
34+
$NoMandatory,
35+
36+
# If provided, will check that dynamic parameters are valid for a given command.
37+
# If the [Management.Automation.CmdletAttribute]
38+
[string[]]
39+
$commandList,
40+
41+
# If provided, will include only these parameters from the input.
42+
[string[]]
43+
$IncludeParameter,
44+
45+
# If provided, will exclude these parameters from the input.
46+
[string[]]
47+
$ExcludeParameter,
48+
49+
# If provided, will make a blank parameter for every -PositionOffset.
50+
# This is so, presumably, whatever has already been provided in these positions will bind correctly.
51+
# The name of this parameter, by default, will be "ArgumentN" (for example, Argument1)
52+
[switch]
53+
$BlankParameter,
54+
55+
# The name of the blank parameter.
56+
# If there is a -PositionOffset, this will make a blank parameter by this name for the position.
57+
[string[]]
58+
$BlankParameterName = "Argument"
59+
)
60+
61+
begin {
62+
$inputQueue = [Collections.Queue]::new()
63+
}
64+
process {
65+
$inputQueue.Enqueue($InputObject)
66+
}
67+
68+
end {
69+
$DynamicParameters = [Management.Automation.RuntimeDefinedParameterDictionary]::new()
70+
71+
if ($PositionOffset -and
72+
($BlankParameter -or $PSBoundParameters['BlankParameterName'])) {
73+
for ($pos =0; $pos -lt $PositionOffset; $pos++) {
74+
$paramName = $BlankParameterName[$pos]
75+
if (-not $paramName) {
76+
$paramName = "$($BlankParameterName[-1])$pos"
77+
}
78+
$DynamicParameters.Add($paramName,
79+
[Management.Automation.RuntimeDefinedParameter]::new(
80+
$paramName,
81+
[PSObject],
82+
@(
83+
$paramAttr = [Management.Automation.ParameterAttribute]::new()
84+
$paramAttr.Position = $pos
85+
$paramAttr
86+
)
87+
)
88+
)
89+
}
90+
}
91+
while ($inputQueue.Count) {
92+
$InputObject = $inputQueue.Dequeue()
93+
94+
$inputCmdMetaData =
95+
if ($inputObject -is [Management.Automation.CommandInfo]) {
96+
[Management.Automation.CommandMetaData]$InputObject
97+
}
98+
elseif ($inputObject -is [scriptblock]) {
99+
$function:TempFunction = $InputObject
100+
[Management.Automation.CommandMetaData]$ExecutionContext.SessionState.InvokeCommand.GetCommand('TempFunction','Function')
101+
}
102+
103+
continue if -not $inputCmdMetaData
104+
105+
:nextDynamicParameter foreach ($paramName in $inputCmdMetaData.Parameters.Keys) {
106+
107+
if ($ExcludeParameter) {
108+
foreach ($exclude in $ExcludeParameter) {
109+
if ($paramName -like $exclude) { continue nextDynamicParameter}
110+
}
111+
}
112+
if ($IncludeParameter) {
113+
$shouldInclude =
114+
foreach ($include in $IncludeParameter) {
115+
if ($paramName -like $include) { $true;break}
116+
}
117+
if (-not $shouldInclude) { continue nextDynamicParameter }
118+
}
119+
120+
$attrList = [Collections.Generic.List[Attribute]]::new()
121+
$validCommandNames = @()
122+
foreach ($attr in $inputCmdMetaData.Parameters[$paramName].attributes) {
123+
if ($attr -isnot [Management.Automation.ParameterAttribute]) {
124+
# we can passthru any non-parameter attributes
125+
$attrList.Add($attr)
126+
# (`[Management.Automation.CmdletAttribute]` is special, as it indicates if the parameter applies to a command)
127+
if ($attr -is [Management.Automation.CmdletAttribute] -and $commandList) {
128+
$validCommandNames += (
129+
($attr.VerbName -replace '\s') + '-' + ($attr.NounName -replace '\s')
130+
) -replace '^\-' -replace '\-$'
131+
}
132+
} else {
133+
# but parameter attributes need to copied.
134+
$attrCopy = [Management.Automation.ParameterAttribute]::new()
135+
# (Side note: without a .Clone, copying is tedious.)
136+
foreach ($prop in $attrCopy.GetType().GetProperties('Instance,Public')) {
137+
if (-not $prop.CanWrite) { continue }
138+
if ($null -ne $attr.($prop.Name)) {
139+
$attrCopy.($prop.Name) = $attr.($prop.Name)
140+
}
141+
}
142+
143+
$attrCopy.ParameterSetName =
144+
if ($ParameterSetName) {
145+
$ParameterSetName
146+
}
147+
else {
148+
$defaultParamSetName = $inputCmdMetaData.DefaultParameterSetName
149+
if ($attrCopy.ParameterSetName -ne '__AllParameterSets') {
150+
$attrCopy.ParameterSetName
151+
}
152+
elseif ($defaultParamSetName) {
153+
$defaultParamSetName
154+
}
155+
elseif ($this -is [Management.Automation.FunctionInfo]) {
156+
$this.Name
157+
} elseif ($this -is [Management.Automation.ExternalScriptInfo]) {
158+
$this.Source
159+
}
160+
}
161+
162+
if ($NoMandatory -and $attrCopy.Mandatory) {
163+
$attrCopy.Mandatory = $false
164+
}
165+
166+
if ($PositionOffset -and $attr.Position -ge 0) {
167+
$attrCopy.Position += $PositionOffset
168+
}
169+
$attrList.Add($attrCopy)
170+
}
171+
}
172+
173+
if ($commandList -and $validCommandNames) {
174+
:CheckCommandValidity do {
175+
foreach ($vc in $validCommandNames) {
176+
if ($commandList -match $vc) { break CheckCommandValidity }
177+
}
178+
continue nextDynamicParameter
179+
} while ($false)
180+
}
181+
182+
if ($DynamicParameters.ContainsKey($paramName)) {
183+
$DynamicParameters[$paramName].ParameterType = [PSObject]
184+
foreach ($attr in $attrList) {
185+
$DynamicParameters[$paramName].Attributes.Add($attr)
186+
}
187+
} else {
188+
$DynamicParameters.Add($paramName, [Management.Automation.RuntimeDefinedParameter]::new(
189+
$inputCmdMetaData.Parameters[$paramName].Name,
190+
$inputCmdMetaData.Parameters[$paramName].ParameterType,
191+
$attrList
192+
))
193+
}
194+
}
195+
}
196+
$DynamicParameters
197+
}
198+
}

0 commit comments

Comments
 (0)