$ErrorActionPreference = 'Stop'
$root = Split-Path -Parent $PSScriptRoot
$coveragePath = Join-Path $PSScriptRoot 'responsive-layout-coverage.json'
$allowlistPath = Join-Path $PSScriptRoot 'responsive-layout-allowlist.json'
if (-not (Test-Path -LiteralPath $coveragePath)) { throw 'Missing responsive layout coverage owner' }
if (-not (Test-Path -LiteralPath $allowlistPath)) { throw 'Missing responsive layout allowlist owner' }
$coverage = Get-Content -LiteralPath $coveragePath -Raw -Encoding UTF8 | ConvertFrom-Json
$allowlist = Get-Content -LiteralPath $allowlistPath -Raw -Encoding UTF8 | ConvertFrom-Json
$requiredFoundation = @(
'components/AppButton.vue',
'components/AppDialog.vue'
)
foreach ($required in $requiredFoundation) {
if ($coverage.covered -notcontains $required) {
throw "Responsive coverage cannot remove migrated foundation file: $required"
}
}
function Normalize-Selector([string]$selector) {
return (($selector -replace '\s+', ' ').Trim())
}
function Test-Allowlisted([string]$path, [string]$selector, [string]$property) {
$normalizedSelector = Normalize-Selector $selector
foreach ($entry in $allowlist.exceptions) {
if ($entry.path -eq $path -and
(Normalize-Selector $entry.selector) -eq $normalizedSelector -and
$entry.property -eq $property) {
return $true
}
}
return $false
}
$violations = [System.Collections.Generic.List[string]]::new()
foreach ($relativePath in $coverage.covered) {
$fullPath = Join-Path $root $relativePath
if (-not (Test-Path -LiteralPath $fullPath)) {
$violations.Add("missing covered file: $relativePath")
continue
}
$source = Get-Content -LiteralPath $fullPath -Raw -Encoding UTF8
$styleMatches = [regex]::Matches($source, '(?is)')
foreach ($styleMatch in $styleMatches) {
$css = $styleMatch.Groups['css'].Value
$ruleMatches = [regex]::Matches($css, '(?ms)(?[^{}]+)\{(?[^{}]*)\}')
foreach ($rule in $ruleMatches) {
$selector = Normalize-Selector $rule.Groups['selector'].Value
$body = $rule.Groups['body'].Value
$checks = @(
@{ Name = 'fixed-height'; Pattern = '(?im)(?