Files

132 lines
4.0 KiB
PowerShell

[CmdletBinding()]
param(
[string[]]$Path = @(
'crates/common/src/formats',
'crates/toon/src',
'crates/ison/src',
'crates/isonl/src',
'crates/zon/src',
'crates/tonl/src'
)
)
$ErrorActionPreference = 'Stop'
Set-StrictMode -Version Latest
$workspaceRoot = Split-Path -Parent $PSScriptRoot
Push-Location -LiteralPath $workspaceRoot
function Get-BraceDelta {
param(
[AllowEmptyString()]
[Parameter(Mandatory = $true)]
[string]$Line
)
$open = ([regex]::Matches($Line, '\{')).Count
$close = ([regex]::Matches($Line, '\}')).Count
return $open - $close
}
function Test-AllowedLine {
param(
[AllowEmptyString()]
[Parameter(Mandatory = $true)]
[string]$Line,
[AllowEmptyString()]
[string]$PreviousLine
)
$sameLineComment = $Line -match '(^|\s)//\s*jade:\s*allow-panic\s+because:\s+\S'
$previousLineComment = -not [string]::IsNullOrWhiteSpace($PreviousLine) -and
$PreviousLine -match '^\s*//\s*jade:\s*allow-panic\s+because:\s+\S'
return $sameLineComment -or (
-not [string]::IsNullOrWhiteSpace($PreviousLine) -and
$previousLineComment
)
}
$patterns = @(
'panic!\s*\(',
'\.unwrap\s*\(',
'\.expect\s*\('
)
$failures = [System.Collections.Generic.List[string]]::new()
try {
foreach ($root in $Path) {
if (-not (Test-Path -LiteralPath $root)) {
throw "No-panic scan path does not exist: $root"
}
$files = Get-ChildItem -LiteralPath $root -Recurse -File -Filter '*.rs'
foreach ($file in $files) {
if (($file.FullName -split '[\\/]') -contains 'tests') {
continue
}
$lines = Get-Content -LiteralPath $file.FullName
$pendingTestModule = $false
$insideTestModule = $false
$braceDepth = 0
$previousLine = ''
for ($index = 0; $index -lt $lines.Count; $index += 1) {
$line = [string]$lines[$index]
$trimmed = $line.TrimStart()
if ($insideTestModule) {
$braceDepth += Get-BraceDelta -Line $line
if ($braceDepth -le 0) {
$insideTestModule = $false
$braceDepth = 0
}
$previousLine = $line
continue
}
if ($trimmed.StartsWith('#[cfg(test)]')) {
$pendingTestModule = $true
$previousLine = $line
continue
}
if ($pendingTestModule -and $trimmed -match '^mod\s+tests\s*\{') {
$insideTestModule = $true
$braceDepth = Get-BraceDelta -Line $line
$pendingTestModule = $false
$previousLine = $line
continue
}
if (-not $trimmed.StartsWith('#[')) {
$pendingTestModule = $false
}
if ($trimmed.StartsWith('//')) {
$previousLine = $line
continue
}
foreach ($pattern in $patterns) {
if ($line -match $pattern -and -not (Test-AllowedLine -Line $line -PreviousLine $previousLine)) {
$relative = Resolve-Path -LiteralPath $file.FullName -Relative
$failures.Add("${relative}:$($index + 1): panic surface requires removal, fallible propagation, or a strict '// jade: allow-panic because: <reason>' comment directly beside this call")
}
}
$previousLine = $line
}
}
}
if ($failures.Count -gt 0) {
$failures | ForEach-Object { Write-Error $_ }
throw "No-panic gate found $($failures.Count) unapproved panic surface(s)."
}
Write-Host "No-panic gate passed for $($Path.Count) root(s)."
}
finally {
Pop-Location
}