Delete directory 'wireframe-system'
This commit is contained in:
@@ -1,291 +0,0 @@
|
||||
param(
|
||||
[Parameter(Mandatory = $false)]
|
||||
[string]$ArtifactDir = "workspace/artifacts/wireframe-gen",
|
||||
|
||||
[Parameter(Mandatory = $false)]
|
||||
[switch]$Strict,
|
||||
|
||||
[Parameter(Mandatory = $false)]
|
||||
[ValidateSet("schema", "pre-ux", "pre-figma")]
|
||||
[string]$Stage = "schema"
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
$errors = New-Object System.Collections.Generic.List[string]
|
||||
|
||||
function Read-Json {
|
||||
param([string]$Path)
|
||||
try {
|
||||
return Get-Content -LiteralPath $Path -Raw -Encoding UTF8 | ConvertFrom-Json
|
||||
}
|
||||
catch {
|
||||
$script:errors.Add("Invalid JSON: $Path - $($_.Exception.Message)")
|
||||
return $null
|
||||
}
|
||||
}
|
||||
|
||||
function Has-Property {
|
||||
param(
|
||||
[object]$Object,
|
||||
[string]$Name
|
||||
)
|
||||
if ($null -eq $Object) { return $false }
|
||||
return $null -ne ($Object.PSObject.Properties | Where-Object { $_.Name -eq $Name })
|
||||
}
|
||||
|
||||
function Test-RequiredFields {
|
||||
param(
|
||||
[object]$Object,
|
||||
[string[]]$Fields,
|
||||
[string]$Label
|
||||
)
|
||||
foreach ($field in $Fields) {
|
||||
if (-not (Has-Property -Object $Object -Name $field)) {
|
||||
$script:errors.Add("$Label missing required field: $field")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function Test-IsNumeric {
|
||||
param([object]$Value)
|
||||
return (
|
||||
$Value -is [byte] -or
|
||||
$Value -is [sbyte] -or
|
||||
$Value -is [int16] -or
|
||||
$Value -is [uint16] -or
|
||||
$Value -is [int32] -or
|
||||
$Value -is [uint32] -or
|
||||
$Value -is [int64] -or
|
||||
$Value -is [uint64] -or
|
||||
$Value -is [single] -or
|
||||
$Value -is [double] -or
|
||||
$Value -is [decimal]
|
||||
)
|
||||
}
|
||||
|
||||
function Test-GridNumber {
|
||||
param(
|
||||
[object]$Value,
|
||||
[string]$Label,
|
||||
[switch]$Positive
|
||||
)
|
||||
|
||||
if (-not (Test-IsNumeric -Value $Value)) {
|
||||
$script:errors.Add("$Label must be numeric")
|
||||
return
|
||||
}
|
||||
|
||||
$number = [double]$Value
|
||||
if ($Positive -and $number -lt 1) {
|
||||
$script:errors.Add("$Label must be at least 1")
|
||||
}
|
||||
|
||||
$rounded = [math]::Round($number)
|
||||
if ([math]::Abs($number - $rounded) -gt 0.000001) {
|
||||
$script:errors.Add("$Label must be a whole number")
|
||||
return
|
||||
}
|
||||
|
||||
if (([int64]$rounded % 4) -ne 0) {
|
||||
$script:errors.Add("$Label must be a multiple of 4")
|
||||
}
|
||||
}
|
||||
|
||||
function Test-LayoutNumbers {
|
||||
param(
|
||||
[object]$Value,
|
||||
[string]$Path = "screen_blueprints"
|
||||
)
|
||||
|
||||
if ($null -eq $Value) { return }
|
||||
|
||||
if ($Value -is [System.Array]) {
|
||||
for ($i = 0; $i -lt $Value.Count; $i++) {
|
||||
Test-LayoutNumbers -Value $Value[$i] -Path "$Path[$i]"
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if (Test-IsNumeric -Value $Value) { return }
|
||||
if ($Value -is [string]) { return }
|
||||
|
||||
$layoutNamePattern = '^(x|y|width|height|minWidth|maxWidth|minHeight|maxHeight|min_width|max_width|min_height|max_height|top|right|bottom|left|padding|paddingTop|paddingRight|paddingBottom|paddingLeft|padding_top|padding_right|padding_bottom|padding_left|margin|marginTop|marginRight|marginBottom|marginLeft|margin_top|margin_right|margin_bottom|margin_left|gap|rowGap|columnGap|row_gap|column_gap|spacing|radius|borderRadius|cornerRadius|border_radius|corner_radius|inset|offset)$'
|
||||
|
||||
foreach ($prop in $Value.PSObject.Properties) {
|
||||
$propPath = "$Path.$($prop.Name)"
|
||||
if ((Test-IsNumeric -Value $prop.Value) -and ($prop.Name -match $layoutNamePattern)) {
|
||||
Test-GridNumber -Value $prop.Value -Label $propPath
|
||||
}
|
||||
elseif ($prop.Value -is [System.Array] -or ($null -ne $prop.Value -and -not ($prop.Value -is [string]) -and -not (Test-IsNumeric -Value $prop.Value) -and $prop.Value.PSObject.Properties.Count -gt 0)) {
|
||||
Test-LayoutNumbers -Value $prop.Value -Path $propPath
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function Get-QuestionStatus {
|
||||
param([object]$Question)
|
||||
if (Has-Property -Object $Question -Name "status" -and -not [string]::IsNullOrWhiteSpace([string]$Question.status)) {
|
||||
return ([string]$Question.status).ToLowerInvariant()
|
||||
}
|
||||
return "unresolved"
|
||||
}
|
||||
|
||||
function Test-QuestionIsResolved {
|
||||
param([object]$Question)
|
||||
$status = Get-QuestionStatus -Question $Question
|
||||
return @("resolved", "answered", "closed") -contains $status
|
||||
}
|
||||
|
||||
function Get-QuestionBlocks {
|
||||
param([object]$Question)
|
||||
if (-not (Has-Property -Object $Question -Name "blocks") -or $null -eq $Question.blocks) {
|
||||
return @()
|
||||
}
|
||||
return @($Question.blocks | ForEach-Object { ([string]$_).ToLowerInvariant() })
|
||||
}
|
||||
|
||||
function Test-QuestionBlocksStage {
|
||||
param(
|
||||
[object]$Question,
|
||||
[string]$StageName
|
||||
)
|
||||
|
||||
$blocks = Get-QuestionBlocks -Question $Question
|
||||
if ($blocks.Count -eq 0) { return $false }
|
||||
|
||||
$common = @("all", "pipeline", "project", "workflow")
|
||||
$preUx = @("ux", "pre-ux", "ux-construction", "ux-constructor", "ux-spec", "screen-blueprints", "screen_blueprints")
|
||||
$preFigma = @("figma", "pre-figma", "figma-build", "figma-generation", "figma-target", "roles", "role", "screens", "screen", "critical-states", "states", "screen-blueprints", "screen_blueprints")
|
||||
|
||||
foreach ($block in $blocks) {
|
||||
if ($common -contains $block) { return $true }
|
||||
if ($StageName -eq "pre-ux" -and $preUx -contains $block) { return $true }
|
||||
if ($StageName -eq "pre-figma" -and $preFigma -contains $block) { return $true }
|
||||
}
|
||||
|
||||
return $false
|
||||
}
|
||||
|
||||
function Test-OpenQuestionGate {
|
||||
param(
|
||||
[object]$NormalizedProject,
|
||||
[string]$StageName
|
||||
)
|
||||
|
||||
if ($StageName -eq "schema" -or $null -eq $NormalizedProject -or -not (Has-Property -Object $NormalizedProject -Name "open_questions")) {
|
||||
return
|
||||
}
|
||||
|
||||
foreach ($question in @($NormalizedProject.open_questions)) {
|
||||
if (-not (Test-QuestionBlocksStage -Question $question -StageName $StageName)) {
|
||||
continue
|
||||
}
|
||||
|
||||
$id = if (Has-Property -Object $question -Name "id") { [string]$question.id } else { "(missing id)" }
|
||||
$text = if (Has-Property -Object $question -Name "question") { [string]$question.question } else { "(missing question text)" }
|
||||
|
||||
if (-not (Test-QuestionIsResolved -Question $question)) {
|
||||
$errors.Add("Open question $id blocks ${StageName}: $text")
|
||||
continue
|
||||
}
|
||||
|
||||
if (-not (Has-Property -Object $question -Name "answer") -or [string]::IsNullOrWhiteSpace([string]$question.answer)) {
|
||||
$errors.Add("Open question $id is resolved for ${StageName} but missing answer")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$contracts = @{
|
||||
"source_inventory.json" = @("generated_at", "input_path", "output_dir", "sources")
|
||||
"normalized_project.json" = @("project", "audiences", "goals", "actors", "functional_modules", "entities", "rules", "constraints", "risks", "open_questions", "source_trace")
|
||||
"ux_spec.json" = @("information_architecture", "user_flows", "screen_inventory", "screen_purposes", "ux_decisions", "research_citations", "acceptance_criteria")
|
||||
"figma_build_manifest.json" = @("file_key", "page", "screen_ids", "created_node_ids", "mutated_node_ids", "screenshots", "validation_notes", "known_issues")
|
||||
}
|
||||
|
||||
$artifactJsons = @{}
|
||||
foreach ($fileName in $contracts.Keys) {
|
||||
$path = Join-Path $ArtifactDir $fileName
|
||||
if (-not (Test-Path -LiteralPath $path)) {
|
||||
if ($Strict) { $errors.Add("Missing artifact: $path") }
|
||||
continue
|
||||
}
|
||||
$json = Read-Json -Path $path
|
||||
$artifactJsons[$fileName] = $json
|
||||
Test-RequiredFields -Object $json -Fields $contracts[$fileName] -Label $fileName
|
||||
}
|
||||
|
||||
if ($artifactJsons.ContainsKey("normalized_project.json")) {
|
||||
Test-OpenQuestionGate -NormalizedProject $artifactJsons["normalized_project.json"] -StageName $Stage
|
||||
}
|
||||
|
||||
$blueprintsPath = Join-Path $ArtifactDir "screen_blueprints.json"
|
||||
if (Test-Path -LiteralPath $blueprintsPath) {
|
||||
$blueprints = Read-Json -Path $blueprintsPath
|
||||
if ($null -ne $blueprints) {
|
||||
$items = @($blueprints)
|
||||
$screenRequired = @("content_type", "screen_id", "viewport", "purpose", "sections", "components", "states", "content_requirements", "interactions", "empty_error_loading_states")
|
||||
$elementRequired = @("content_type", "element_id", "parent_screen_id", "bounds")
|
||||
for ($i = 0; $i -lt $items.Count; $i++) {
|
||||
$item = $items[$i]
|
||||
$label = "screen_blueprints[$i]"
|
||||
Test-RequiredFields -Object $item -Fields @("content_type") -Label $label
|
||||
|
||||
if (-not (Has-Property -Object $item -Name "content_type")) {
|
||||
continue
|
||||
}
|
||||
|
||||
switch ($item.content_type) {
|
||||
"screen" {
|
||||
Test-RequiredFields -Object $item -Fields $screenRequired -Label $label
|
||||
if (Has-Property -Object $item -Name "viewport") {
|
||||
Test-RequiredFields -Object $item.viewport -Fields @("width", "height") -Label "$label.viewport"
|
||||
if (Has-Property -Object $item.viewport -Name "width") {
|
||||
Test-GridNumber -Value $item.viewport.width -Label "$label.viewport.width" -Positive
|
||||
if ([double]$item.viewport.width -ne 1440) {
|
||||
$errors.Add("$label.viewport.width must equal 1440 for content_type screen")
|
||||
}
|
||||
}
|
||||
if (Has-Property -Object $item.viewport -Name "height") {
|
||||
Test-GridNumber -Value $item.viewport.height -Label "$label.viewport.height" -Positive
|
||||
if ([double]$item.viewport.height -lt 800) {
|
||||
$errors.Add("$label.viewport.height must be at least 800 for content_type screen")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"element" {
|
||||
Test-RequiredFields -Object $item -Fields $elementRequired -Label $label
|
||||
if (Has-Property -Object $item -Name "bounds") {
|
||||
Test-RequiredFields -Object $item.bounds -Fields @("width", "height") -Label "$label.bounds"
|
||||
foreach ($field in @("x", "y", "width", "height")) {
|
||||
if (Has-Property -Object $item.bounds -Name $field) {
|
||||
$positive = $field -eq "width" -or $field -eq "height"
|
||||
if ($positive) {
|
||||
Test-GridNumber -Value $item.bounds.$field -Label "$label.bounds.$field" -Positive
|
||||
}
|
||||
else {
|
||||
Test-GridNumber -Value $item.bounds.$field -Label "$label.bounds.$field"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
default {
|
||||
$errors.Add("$label.content_type must be either screen or element")
|
||||
}
|
||||
}
|
||||
|
||||
Test-LayoutNumbers -Value $item -Path $label
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif ($Strict) {
|
||||
$errors.Add("Missing artifact: $blueprintsPath")
|
||||
}
|
||||
|
||||
if ($errors.Count -gt 0) {
|
||||
$errors | ForEach-Object { Write-Error $_ }
|
||||
exit 1
|
||||
}
|
||||
|
||||
Write-Output "Artifact validation passed for $ArtifactDir"
|
||||
Reference in New Issue
Block a user