Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# The PowerShell script binder consumes a bare -- before populating $args.
# Exercise the generated wrapper with a real native child, without a registry.
function Assert-Arguments($actual, $expected) {
if ($LASTEXITCODE -ne 0 -or ($actual -join "`n") -ne $expected) {
throw "Expected arguments $expected, got $actual (exit $LASTEXITCODE)"
}
}

Assert-Arguments (vp env exec node print-args.cjs -- --template react-ts) '["--","--template","react-ts"]'
Assert-Arguments (vp env exec node print-args.cjs '--' --template react-ts) '["--","--template","react-ts"]'
Assert-Arguments (vp env exec node print-args.cjs "--" --template react-ts) '["--","--template","react-ts"]'
Assert-Arguments (vp env exec node print-args.cjs '--' -- --template react-ts) '["--","--","--template","react-ts"]'
Assert-Arguments (vp env exec node print-args.cjs -- -- --template react-ts) '["--","--","--template","react-ts"]'
Assert-Arguments (vp env exec node print-args.cjs --) '["--"]'
Assert-Arguments (vp env exec node print-args.cjs 'value with spaces' -- --template 'react ts') '["value with spaces","--","--template","react ts"]'

$prefix = @('env', 'exec', 'node', 'print-args.cjs')
$suffix = @('--template', 'react-ts')
$allArguments = $prefix + @('--') + $suffix
Assert-Arguments (vp @prefix -- --template react-ts) '["--","--template","react-ts"]'
Assert-Arguments (vp env exec node print-args.cjs -- @suffix) '["--","--template","react-ts"]'
Assert-Arguments (vp @prefix -- @suffix) '["--","--template","react-ts"]'
Assert-Arguments (vp @allArguments) '["--","--template","react-ts"]'
$emptyArguments = @()
Assert-Arguments (vp @prefix @emptyArguments -- @emptyArguments @suffix) '["--","--template","react-ts"]'
Assert-Arguments (vp env exec node print-args.cjs @('before', 'separator') -- @('after', 'separator')) '["before","separator","--","after","separator"]'

# The caller AST must identify the invocation inside a function or on a later line.
function Invoke-ArgumentCheck {
Assert-Arguments (vp @prefix -- @suffix) '["--","--template","react-ts"]'
}
Invoke-ArgumentCheck
Assert-Arguments (& vp env exec node print-args.cjs `
-- `
--template react-ts) '["--","--template","react-ts"]'
Assert-Arguments (vp env exec node print-args.cjs first -- second | ForEach-Object { $_ }) '["first","--","second"]'

# Recovering the separator must not evaluate argument expressions a second time.
$script:argumentEvaluations = 0
Assert-Arguments (vp env exec node print-args.cjs -- $($script:argumentEvaluations++; 'value with spaces')) '["--","value with spaces"]'
if ($script:argumentEvaluations -ne 1) { throw 'An argument expression ran more than once' }

Assert-Arguments (vp env exec node print-args.cjs 'text -- with spaces' --template react-ts) '["text -- with spaces","--template","react-ts"]'
Assert-Arguments (vp env exec node print-args.cjs `-- --template react-ts) '["--","--template","react-ts"]'
Assert-Arguments (vp env exec node print-args.cjs --template react-ts) '["--template","react-ts"]'
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ if ($env:VP_NODE_VERSION -ne "22.18.0") {
throw "file-based VP_NODE_VERSION mismatch: expected 22.18.0, got $env:VP_NODE_VERSION"
}

. (Join-Path $PSScriptRoot "assert-arguments.ps1")
. (Join-Path $PSScriptRoot "assert-status.ps1")

Write-Output "PowerShell environment checks passed"
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
console.log(JSON.stringify(process.argv.slice(2)));
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,60 @@ PowerShell wrapper keeps global -C before env use and propagates the native exit
```
# Vite+ PowerShell wrapper (https://viteplus.dev)
$__vp_bin = '<workspace>/home/bin'
# PowerShell consumes the first bare -- when calling a script. Recover its
# position from the caller's AST, without evaluating argument expressions again.
# The call stack also works on Windows PowerShell 5.1, which has no Statement.
$__vp_stack = @(Get-PSCallStack)
$__vp_command = $null
if ($__vp_stack.Count -gt 1) {
$__vp_ast = $__vp_stack[1].InvocationInfo.MyCommand.ScriptBlock.Ast
$__vp_line = $MyInvocation.ScriptLineNumber
$__vp_column = $MyInvocation.OffsetInLine
if ($__vp_ast) {
$__vp_command = $__vp_ast.Find({ param($node)
$node -is [System.Management.Automation.Language.CommandAst] -and
$node.Extent.StartLineNumber -eq $__vp_line -and $node.Extent.StartColumnNumber -eq $__vp_column
}, $true)
}
}
if ($__vp_command) {
$__vp_elements = $__vp_command.CommandElements
for ($__vp_i = 1; $__vp_i -lt $__vp_elements.Count; $__vp_i++) {
if ($__vp_elements[$__vp_i].Extent.Text -ceq '--') {
$__vp_index = 0
for ($__vp_j = 1; $__vp_j -lt $__vp_i; $__vp_j++) {
$__vp_element = $__vp_elements[$__vp_j]
if ($__vp_element -is [System.Management.Automation.Language.VariableExpressionAst] -and $__vp_element.Splatted) {
# Count from the end when the prefix has a variable length.
$__vp_index = $args.Count
for ($__vp_k = $__vp_i + 1; $__vp_k -lt $__vp_elements.Count; $__vp_k++) {
$__vp_tail = $__vp_elements[$__vp_k]
if ($__vp_tail -is [System.Management.Automation.Language.VariableExpressionAst] -and $__vp_tail.Splatted) {
$__vp_value = $ExecutionContext.SessionState.PSVariable.GetValue($__vp_tail.VariablePath.UserPath)
if ($__vp_value -is [System.Collections.IDictionary]) {
$__vp_index -= 2 * $__vp_value.Count
} else {
$__vp_index -= @($__vp_value).Count
}
} else {
$__vp_index--
}
}
break
}
$__vp_index++
if ($__vp_element -is [System.Management.Automation.Language.CommandParameterAst] -and $__vp_element.Argument) {
$__vp_index++
}
}
$__vp_arguments = [System.Collections.Generic.List[object]]::new()
$__vp_arguments.AddRange($args)
$__vp_arguments.Insert($__vp_index, '--')
$args = $__vp_arguments.ToArray()
break
}
}
}
$__vp_command_index = 0
if ($args.Count -ge 1) {
if ($args[0] -eq "-C") {
Expand Down
54 changes: 54 additions & 0 deletions crates/vp_global_cli/src/commands/env/setup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1037,6 +1037,60 @@ Register-ArgumentCompleter -Native -CommandName vpr -ScriptBlock $__vpr_comp
// PowerShell consuming common parameters such as -Verbose or its -V alias.
const VP_WRAPPER_PS1: &str = r#"# Vite+ PowerShell wrapper (https://viteplus.dev)
$__vp_bin = '__VP_BIN_WIN__'
# PowerShell consumes the first bare -- when calling a script. Recover its
# position from the caller's AST, without evaluating argument expressions again.
# The call stack also works on Windows PowerShell 5.1, which has no Statement.
$__vp_stack = @(Get-PSCallStack)
$__vp_command = $null
if ($__vp_stack.Count -gt 1) {
$__vp_ast = $__vp_stack[1].InvocationInfo.MyCommand.ScriptBlock.Ast
$__vp_line = $MyInvocation.ScriptLineNumber
$__vp_column = $MyInvocation.OffsetInLine
if ($__vp_ast) {
$__vp_command = $__vp_ast.Find({ param($node)
$node -is [System.Management.Automation.Language.CommandAst] -and
$node.Extent.StartLineNumber -eq $__vp_line -and $node.Extent.StartColumnNumber -eq $__vp_column
}, $true)
}
}
if ($__vp_command) {
$__vp_elements = $__vp_command.CommandElements
for ($__vp_i = 1; $__vp_i -lt $__vp_elements.Count; $__vp_i++) {
if ($__vp_elements[$__vp_i].Extent.Text -ceq '--') {
$__vp_index = 0
for ($__vp_j = 1; $__vp_j -lt $__vp_i; $__vp_j++) {
$__vp_element = $__vp_elements[$__vp_j]
if ($__vp_element -is [System.Management.Automation.Language.VariableExpressionAst] -and $__vp_element.Splatted) {
# Count from the end when the prefix has a variable length.
$__vp_index = $args.Count
for ($__vp_k = $__vp_i + 1; $__vp_k -lt $__vp_elements.Count; $__vp_k++) {
$__vp_tail = $__vp_elements[$__vp_k]
if ($__vp_tail -is [System.Management.Automation.Language.VariableExpressionAst] -and $__vp_tail.Splatted) {
$__vp_value = $ExecutionContext.SessionState.PSVariable.GetValue($__vp_tail.VariablePath.UserPath)
if ($__vp_value -is [System.Collections.IDictionary]) {
$__vp_index -= 2 * $__vp_value.Count
} else {
$__vp_index -= @($__vp_value).Count
}
} else {
$__vp_index--
}
}
break
}
$__vp_index++
if ($__vp_element -is [System.Management.Automation.Language.CommandParameterAst] -and $__vp_element.Argument) {
$__vp_index++
}
}
$__vp_arguments = [System.Collections.Generic.List[object]]::new()
$__vp_arguments.AddRange($args)
$__vp_arguments.Insert($__vp_index, '--')
$args = $__vp_arguments.ToArray()
break
}
}
}
$__vp_command_index = 0
if ($args.Count -ge 1) {
if ($args[0] -eq "-C") {
Expand Down
Loading