$ErrorActionPreference = 'Stop' $root = Split-Path $PSScriptRoot -Parent $allowlistPath = Join-Path $PSScriptRoot 'document-flow-position-allowlist.json' $allowlist = Get-Content -LiteralPath $allowlistPath -Raw -Encoding UTF8 | ConvertFrom-Json $allowed = @{} $seenAllowed = @{} foreach ($entry in $allowlist) { $allowed["$($entry.file)::$($entry.selector)"] = $entry.reason } $violations = New-Object System.Collections.Generic.List[string] $files = Get-ChildItem -LiteralPath (Join-Path $root 'pages'), (Join-Path $root 'components') -Recurse -File -Filter '*.vue' foreach ($file in $files) { $relative = $file.FullName.Substring($root.Length + 1).Replace('\', '/') $source = [System.IO.File]::ReadAllText($file.FullName, [System.Text.Encoding]::UTF8) foreach ($styleMatch in [regex]::Matches($source, '(?s)]*>(?.*?)')) { $css = $styleMatch.Groups['css'].Value foreach ($rule in [regex]::Matches($css, '(?s)(?[^{}]+)\{(?[^{}]*)\}')) { $body = [regex]::Replace($rule.Groups['body'].Value, '(?s)/\*.*?\*/', '') $positionMatches = [regex]::Matches($body, '(?im)(?[^;{}]+?)\s*;') if ($positionMatches.Count -eq 0) { continue } $selector = (($rule.Groups['selector'].Value -replace '(?s)^.*@media[^\{]*', '') -replace '\s+', ' ').Trim() $key = "$relative::$selector" if ($allowed.ContainsKey($key)) { $seenAllowed[$key] = $true } else { foreach ($positionMatch in $positionMatches) { $position = ($positionMatch.Groups['value'].Value -replace '\s+', ' ').Trim() $violations.Add("$relative :: $selector :: position:$position") } } } } } $staleAllowlistEntries = @($allowed.Keys | Where-Object { -not $seenAllowed.ContainsKey($_) } | Sort-Object) if ($staleAllowlistEntries.Count -gt 0) { $staleAllowlistEntries | ForEach-Object { Write-Output "STALE ALLOWLIST :: $_" } throw "DOCUMENT-FLOW-POSITION-CONTRACT found $($staleAllowlistEntries.Count) stale allowlist entries." } if ($violations.Count -gt 0) { $violations | Sort-Object | ForEach-Object { Write-Output $_ } throw "DOCUMENT-FLOW-POSITION-CONTRACT found $($violations.Count) non-allowlisted position declarations." } Write-Output 'DOCUMENT-FLOW-POSITION-CONTRACT PASS'