@@ -88,24 +88,90 @@ function Sync-BinScripts {
8888 # 构建源文件的相对路径 (假设 bin 和 scripts 都在项目根目录下)
8989 $sourceRelPath = Join-Path ' ..' (Join-Path ' scripts' (Join-Path ' pwsh' $relativePath ))
9090
91- # 生成 Shim 内容
92- $shimContent = @ (
93- " #!/usr/bin/env pwsh" ,
94- " " ,
95- " # Auto-generated shim by Manage-BinScripts.ps1" ,
96- " # Source: $ ( $script.FullName ) " ,
97- " " ,
98- " `$ SourcePath = Join-Path `$ PSScriptRoot '$sourceRelPath '" ,
99- " if (-not (Test-Path `$ SourcePath)) {" ,
100- " Write-Error "" Cannot find source script at `$ SourcePath"" " ,
101- " exit 1" ,
102- " }" ,
103- " & `$ SourcePath @args" ,
104- " exit `$ LASTEXITCODE"
105- )
91+ # --- 解析源脚本元数据 (Help, Param, CmdletBinding) ---
92+ $sourceContent = Get-Content - Path $script.FullName - Raw
93+ $tokens = $null
94+ $errors = $null
95+ $ast = [System.Management.Automation.Language.Parser ]::ParseInput($sourceContent , [ref ]$tokens , [ref ]$errors )
96+
97+ $paramBlockText = $null
98+ $helpText = $null
99+ $hasCmdletBinding = $false
100+
101+ # 1. 提取 ParamBlock
102+ if ($ast.ParamBlock ) {
103+ $paramBlockText = $ast.ParamBlock.Extent.Text
104+
105+ # 检查是否有 CmdletBinding
106+ foreach ($attr in $ast.ParamBlock.Attributes ) {
107+ if ($attr.TypeName.FullName -match ' CmdletBinding' ) {
108+ $hasCmdletBinding = $true
109+ # 尝试获取完整的 CmdletBinding 定义 (包括参数)
110+ $cmdletBindingText = $attr.Extent.Text
111+ break
112+ }
113+ }
114+ }
115+
116+ # 2. 提取 HelpComment
117+ # 简单策略:查找第一个包含 .SYNOPSIS 或 .DESCRIPTION 的块注释
118+ foreach ($token in $tokens ) {
119+ if ($token.Kind -eq ' Comment' -and $token.Text -match ' ^\s*<#\s*\.(SYNOPSIS|DESCRIPTION)' ) {
120+ $helpText = $token.Text
121+ break
122+ }
123+ }
124+
125+ # --- 生成 Shim 内容 ---
126+ $shimContentLines = @ ()
127+ $shimContentLines += " #!/usr/bin/env pwsh"
128+ $shimContentLines += " "
129+ $shimContentLines += " # Auto-generated shim by Manage-BinScripts.ps1"
130+ $shimContentLines += " # Source: $ ( $script.FullName ) "
131+ $shimContentLines += " "
132+
133+ if (-not [string ]::IsNullOrWhiteSpace($helpText )) {
134+ $shimContentLines += $helpText
135+ $shimContentLines += " "
136+ }
137+
138+ if ($hasCmdletBinding ) {
139+ $shimContentLines += $cmdletBindingText
140+ }
141+ elseif ($null -ne $paramBlockText ) {
142+ # 如果有 param 但没有 CmdletBinding,为了支持高级功能(如 -Verbose),最好加上
143+ # 但为了保持原意,如果源脚本没加,我们也不加(除非为了 splatting 需要?)
144+ # 通常建议加上 [CmdletBinding()]
145+ $shimContentLines += " [CmdletBinding()]"
146+ }
147+
148+ if (-not [string ]::IsNullOrWhiteSpace($paramBlockText )) {
149+ $shimContentLines += $paramBlockText
150+ $shimContentLines += " "
151+ }
152+
153+ $shimContentLines += " `$ SourcePath = Join-Path `$ PSScriptRoot '$sourceRelPath '"
154+ $shimContentLines += " if (-not (Test-Path `$ SourcePath)) {"
155+ $shimContentLines += " Write-Error "" Cannot find source script at `$ SourcePath"" "
156+ $shimContentLines += " exit 1"
157+ $shimContentLines += " }"
158+
159+ # 调用逻辑
160+ if (-not [string ]::IsNullOrWhiteSpace($paramBlockText )) {
161+ # 使用 @PSBoundParameters 透传绑定参数
162+ # 注意:如果 Shim 还有其他非绑定参数(如 $args),这里会丢失
163+ # 但既然有了 ParamBlock,通常只应该传递绑定的参数
164+ $shimContentLines += " & `$ SourcePath @PSBoundParameters"
165+ }
166+ else {
167+ # 无 ParamBlock,透传所有 args
168+ $shimContentLines += " & `$ SourcePath @args"
169+ }
170+
171+ $shimContentLines += " exit `$ LASTEXITCODE"
106172
107173 # 写入 Shim 文件
108- $shimContent | Set-Content - Path $targetPath - Encoding utf8NoBOM - Force
174+ $shimContentLines | Set-Content - Path $targetPath - Encoding utf8NoBOM - Force
109175
110176 # 在 Linux/macOS 上设置可执行权限
111177 if (-not $IsWindows ) {
0 commit comments