$ErrorActionPreference = 'Stop' $root = Split-Path -Parent $PSScriptRoot $manifestRelativePath = 'docs/design/assets/a01-vnext/source/a01-psd-manifest.json' function ConvertFrom-Utf8Base64 { param([string]$Value) return [Text.Encoding]::UTF8.GetString([Convert]::FromBase64String($Value)) } $requiredFiles = @( $manifestRelativePath, 'scripts/build-a01-layered-psd.ps1', 'scripts/export-a01-layered-assets.ps1', 'scripts/photoshop/a01-build-layered-psd.jsx', 'scripts/photoshop/a01-export-layered-assets.jsx', 'scripts/photoshop/a01-compose-page-preview.jsx' ) foreach ($relativePath in $requiredFiles) { $absolutePath = Join-Path $root $relativePath if (-not (Test-Path -LiteralPath $absolutePath -PathType Leaf)) { throw "Missing layered PSD contract file: $relativePath" } } $manifestPath = Join-Path $root $manifestRelativePath $manifest = Get-Content -LiteralPath $manifestPath -Raw -Encoding utf8 | ConvertFrom-Json if ($manifest.schemaVersion -ne 1) { throw "Expected PSD manifest schemaVersion 1, found $($manifest.schemaVersion)." } if ($manifest.canvas.width -ne 1236 -or $manifest.canvas.height -ne 2745) { throw 'PSD canvas must be 1236x2745.' } if ($manifest.canvas.logicalWidth -ne 412 -or $manifest.canvas.logicalHeight -ne 915 -or $manifest.canvas.scale -ne 3) { throw 'PSD logical canvas must be 412x915 at scale 3.' } $requiredGroups = @( 'MDAt5Y+C6ICD', 'MTAt6IOM5pmv', 'MjAt5Y236L20', 'MzAt5ZOB54mM5LiO5qCH6aKY6KOF6aWw', 'NDAt5YWs5YWx5o6n5Lu255qu6IKk', 'NTAt5a+G56CB55m75b2V', 'NjAt6aqM6K+B56CB55m75b2V', 'NzAt5YaF5a655LiO5qCH5rOo' ) | ForEach-Object { ConvertFrom-Utf8Base64 $_ } foreach ($groupName in $requiredGroups) { if ($manifest.groups.name -notcontains $groupName) { throw "Missing PSD group: $groupName" } } foreach ($stateName in @('password-hidden', 'password-visible', 'sms-default', 'sms-countdown')) { if ($manifest.states.name -notcontains $stateName) { throw "Missing PSD state: $stateName" } } $buildWrapper = Get-Content -LiteralPath (Join-Path $root 'scripts/build-a01-layered-psd.ps1') -Raw -Encoding utf8 $exportWrapper = Get-Content -LiteralPath (Join-Path $root 'scripts/export-a01-layered-assets.ps1') -Raw -Encoding utf8 $buildJsx = Get-Content -LiteralPath (Join-Path $root 'scripts/photoshop/a01-build-layered-psd.jsx') -Raw -Encoding utf8 $exportJsx = Get-Content -LiteralPath (Join-Path $root 'scripts/photoshop/a01-export-layered-assets.jsx') -Raw -Encoding utf8 $composeJsx = Get-Content -LiteralPath (Join-Path $root 'scripts/photoshop/a01-compose-page-preview.jsx') -Raw -Encoding utf8 foreach ($wrapper in @($buildWrapper, $exportWrapper)) { foreach ($variableName in @('JIAPU_A01_ROOT', 'JIAPU_A01_MANIFEST', 'JIAPU_A01_PSD')) { if ($wrapper -notmatch [regex]::Escape("var $variableName =")) { throw "Photoshop wrapper must inject the JSX variable directly: $variableName" } } } foreach ($jsx in @($buildJsx, $exportJsx)) { if ($jsx -match [regex]::Escape('$.getenv(')) { throw 'Photoshop JSX must not depend on environment variables from an already-running process.' } } if ($composeJsx -notmatch [regex]::Escape('new Folder(JIAPU_A01_ROOT)') -or $composeJsx -notmatch [regex]::Escape('new Folder(JIAPU_A01_OUTPUT_DIR)')) { throw 'Photoshop preview composer must construct Folder objects explicitly.' } if ($composeJsx -match [regex]::Escape("var password = app.open(File(OUTPUT.fsName + '/A01-page-password-v1-1236x2745.png'))")) { throw 'Contact-sheet composition must not pre-open a source that placeImage opens itself.' } Write-Output 'A01-LAYERED-PSD-CONTRACT PASS'