# 注释规范合规检查:文件级注释 ≤3 行且 ≤90 字,函数级注释 ≤30 字 # 有问题的文件不静默:问题数大于 0 时退出码为 1 param([string]$Root = (Split-Path -Parent $PSScriptRoot), [string[]]$Only) $codeDirs = @('chusql-core','chusql-server','chusql-web','chusql-cli','chusql-bootstrap','chusql-interface','chusql-benchmark','scripts','gate-check') $files = @() foreach ($d in $codeDirs) { $p = Join-Path $Root $d if (Test-Path -LiteralPath $p) { $files += Get-ChildItem -LiteralPath $p -Recurse -File -Include *.hs,*.rs,*.js,*.css,*.html,*.ps1,*.sh | Where-Object { $_.FullName -notmatch '\\\.stack-work\\|\\dist-newstyle\\|\\target\\|\\node_modules\\|\\logs\\|\\tmp\\' } } } if ($Only) { $files = $files | Where-Object { $n = $_.Name; ($Only | Where-Object { $n -like $_ }).Count -gt 0 } } $files = $files | Sort-Object FullName $files = $files | Where-Object { $_.FullName -notmatch '\\localdata\\' } $problems = @() $scanned = 0 $fnCount = 0 $fileBlockCount = 0 foreach ($f in $files) { $lines = @(Get-Content -LiteralPath $f.FullName) $ext = $f.Extension.ToLower() $scanned++ # ---- 函数级注释长度(只查每个函数/方法的“摘要行”:连续 doc 注释组第一行;# Safety 小节与非函数声明不计)---- $docRe = '^\s*(--\s*\|\s?|///\s?|//!\s?)(.*)$' for ($i = 0; $i -lt $lines.Count; $i++) { $l = $lines[$i] $body = $null if ($l -notmatch $docRe) { if ($ext -eq '.js' -and $l -match '^\s*//\s?(.*)$') { $body = $Matches[1] } else { continue } } else { $body = $Matches[2] } if ($i -gt 0) { $prev = $lines[$i - 1] $prevDoc = ($prev -match $docRe) -or ($ext -eq '.js' -and $prev -match '^\s*//\s?') if ($prevDoc) { continue } } $k = $i while ($k -lt $lines.Count -and (($lines[$k] -match $docRe) -or ($lines[$k] -match '^\s*#\[') -or ($ext -eq '.js' -and $lines[$k] -match '^\s*//'))) { $k++ } $decl = if ($k -lt $lines.Count) { $lines[$k] } else { '' } $isFn = switch ($ext) { '.rs' { $decl -match '\bfn\s' } '.hs' { $decl -match '^\s*[a-z_][A-Za-z0-9_'']*\s*::' } '.js' { ($decl -match '^\s*(export\s+)?(async\s+)?function\b') -or ($decl -match '^\s*(export\s+)?(const|let|var)\s+[A-Za-z_$][\w$]*\s*=\s*(async\s*)?(function\b|\()') } default { $false } } if (-not $isFn) { continue } $t = $body.Trim() if ($t -eq '' -or $t[0] -eq '#') { continue } $fnCount++ if ($t.Length -gt 30) { $problems += [pscustomobject]@{ Kind = 'FN-LONG'; File = $f.FullName; Line = $i + 1; Info = "$($t.Length)字 $t" } } } # ---- 找出“外部引用”最后一行(含跨行的 import{...} / param(...) 块)---- $lastRef = -1 for ($i = 0; $i -lt $lines.Count; $i++) { $l = $lines[$i] $hit = $false if ($l -match '^(import|use)\s' -or $l -match '^#\[macro_use\]' -or $l -match '^\s*#include\s' -or $l -match '^@import\s' -or $l -match '^\s*' }) } } else { $fileBlockCount++ } } else { $fileBlockCount++ $chars = 0 foreach ($b in $block) { $t = $b -replace '^\s*(--|//|#|/\*|\*|