$ErrorActionPreference = 'Stop' function Assert-Match { param([string]$Content, [string]$Pattern, [string]$Message) if ($Content -notmatch $Pattern) { throw $Message } } function Assert-NoCssSurface { param([string]$Content, [string]$ClassName) foreach ($property in @('border', 'background', 'border-radius')) { $pattern = "(?s)\\.$ClassName\\s*\\{[^}]*\\b$property\\s*:" if ($Content -match $pattern) { throw "G01 empty state must not construct .$ClassName with CSS $property" } } } $root = Split-Path -Parent $PSScriptRoot $pages = Get-Content -LiteralPath (Join-Path $root 'pages.json') -Raw -Encoding utf8 | ConvertFrom-Json $paths = @($pages.pages.path) $g01 = Get-Content -LiteralPath (Join-Path $root 'pages/genealogy/g01-my-genealogies.vue') -Raw -Encoding utf8 $panelPath = Join-Path $root 'static/assets/modules/genealogy/opaque/g01-empty-panel.png' if (-not ($paths -contains 'pages/genealogy/g01-my-genealogies')) { throw 'G01 route missing' } if ($paths -contains 'pages/genealogy/g02-empty-genealogies') { throw 'G02 route must be removed; empty state belongs to G01' } foreach ($required in @( 'forceEmptyState', 'query.get("state") === "empty"', 'g01-empty-panel.png', 'empty-create-action', 'empty-search-action', 'const createGenealogy = () =>', '/pages/genealogy/g03-create-genealogy', '/pages/genealogy/g06-search-genealogies', 'const hasGenealogies = computed(() => !forceEmptyState.value && list.value.length > 0);' )) { if ($g01 -notmatch [regex]::Escape($required)) { throw "Missing G01 empty-state contract: $required" } } foreach ($className in @('empty-panel', 'empty-create-action', 'empty-search-action')) { Assert-NoCssSurface -Content $g01 -ClassName $className } if (-not (Test-Path -LiteralPath $panelPath)) { throw 'G01 requires its final raster empty-panel asset' } Add-Type -AssemblyName System.Drawing $panel = [System.Drawing.Bitmap]::FromFile($panelPath) try { if ($panel.Width -ne 1122 -or $panel.Height -ne 1402) { throw 'G01 empty-panel asset must remain 1122 x 1402px' } $corners = @( $panel.GetPixel(0, 0).A, $panel.GetPixel(($panel.Width - 1), 0).A, $panel.GetPixel(0, ($panel.Height - 1)).A, $panel.GetPixel(($panel.Width - 1), ($panel.Height - 1)).A ) if (($corners | Where-Object { $_ -ne 255 }).Count -ne 0) { throw 'G01 empty-panel asset must have opaque outer corners' } } finally { $panel.Dispose() } Write-Output 'G01-EMPTY-STATE-CONTRACT PASS'