# Skara Brae — EA model exporter (WI-2), adapted from keyfob-station's # export-model-json.ps1 (COM walk of the model -> machine-readable JSON). # # Regenerates (generated files — never hand-edit): # docs/openup/model/exports/use-case-model.json (actors, use cases, scenarios, steps) # docs/openup/model/exports/uc-realizations.json (realization packages + elements) # docs/openup/model/exports/xmi-backup.xml (lossless EA XMI 2.1 export of the root) # # Drift rule: markdown (use-case-model.md, uc-realization-mapping.md) and the model must # agree; a mismatch is a defect fixed in the same cycle. uc-realizations.json content must # match what scripts/openup/markdown-to-json.py generated from mapping §2. # # Platform: Windows + installed EA (design §11.c). If COM automation hits friction, the # fallback is EA's manual Publish -> XML export into exports/ (see model/README.md). $ErrorActionPreference = 'Stop' $repoRoot = (Resolve-Path (Join-Path $PSScriptRoot '..\..')).Path $modelPath = Join-Path $repoRoot 'docs\openup\model\skara-brae.eapx' if (-not (Test-Path $modelPath)) { Write-Output "MISSING $modelPath - nothing to export" exit 1 } $exportsDir = Join-Path $repoRoot 'docs\openup\model\exports' New-Item -ItemType Directory -Force -Path $exportsDir | Out-Null $ucOutPath = Join-Path $exportsDir 'use-case-model.json' $realOutPath = Join-Path $exportsDir 'uc-realizations.json' $xmiOutPath = Join-Path $exportsDir 'xmi-backup.xml' $app = $null $eaBefore = @(Get-Process -Name EA -ErrorAction SilentlyContinue | Select-Object -ExpandProperty Id) try { $app = New-Object -ComObject EA.App $app.Visible = $false $repo = $app.Repository $null = $repo.OpenFile($modelPath) $root = $repo.Models.GetAt([int]0) # ---------- Requirements / Use Case Model ---------- $ucModel = $root.Packages.GetByName('Requirements').Packages.GetByName('Use Case Model') $actors = @() $useCases = @() for ($i = 0; $i -lt $ucModel.Elements.Count; $i++) { $element = $ucModel.Elements.GetAt([int]$i) if ($element.Type -eq 'Actor') { $actors += [ordered]@{ name = $element.Name; notes = $element.Notes } } } for ($i = 0; $i -lt $ucModel.Elements.Count; $i++) { $element = $ucModel.Elements.GetAt([int]$i) if ($element.Type -ne 'UseCase') { continue } $associatedActors = @() for ($c = 0; $c -lt $element.Connectors.Count; $c++) { $connector = $element.Connectors.GetAt([int]$c) if ($connector.Type -ne 'Association') { continue } $otherId = if ($connector.ClientID -eq $element.ElementID) { $connector.SupplierID } else { $connector.ClientID } $other = $repo.GetElementByID($otherId) if ($other.Type -eq 'Actor') { $associatedActors += $other.Name } } $scenarios = @() $element.Scenarios.Refresh() for ($s = 0; $s -lt $element.Scenarios.Count; $s++) { $scenario = $element.Scenarios.GetAt([int]$s) $steps = @() $scenario.Steps.Refresh() for ($t = 0; $t -lt $scenario.Steps.Count; $t++) { $scenarioStep = $scenario.Steps.GetAt([int]$t) $steps += [ordered]@{ actor = $scenarioStep.StepType; text = $scenarioStep.Name } } $scenarios += [ordered]@{ name = $scenario.Name type = $scenario.Type notes = $scenario.Notes steps = $steps } } $useCases += [ordered]@{ name = $element.Name notes = $element.Notes actors = $associatedActors scenarios = $scenarios } } $ucPayload = [ordered]@{ exportedFrom = 'docs/openup/model/skara-brae.eapx (Requirements/Use Case Model)' actors = $actors useCases = $useCases } [System.IO.File]::WriteAllText($ucOutPath, ($ucPayload | ConvertTo-Json -Depth 8), [System.Text.Encoding]::UTF8) Write-Output "exported: $ucOutPath ($($useCases.Count) use cases, $($actors.Count) actors)" # ---------- Analysis-Design realizations ---------- $analysisDesign = $root.Packages.GetByName('Analysis-Design') $realizations = @() for ($p = 0; $p -lt $analysisDesign.Packages.Count; $p++) { $realizationPackage = $analysisDesign.Packages.GetAt([int]$p) if ($realizationPackage.Name -notlike 'UC-?? Realization') { continue } $realizationPackage.Elements.Refresh() $useCaseName = '' $classes = @() for ($e = 0; $e -lt $realizationPackage.Elements.Count; $e++) { $element = $realizationPackage.Elements.GetAt([int]$e) if ($element.Type -eq 'Collaboration') { $element.Connectors.Refresh() for ($c = 0; $c -lt $element.Connectors.Count; $c++) { $connector = $element.Connectors.GetAt([int]$c) if (($connector.Type -eq 'Realization' -or $connector.Type -eq 'Realisation') -and $connector.ClientID -eq $element.ElementID) { $useCaseName = $repo.GetElementByID($connector.SupplierID).Name } } } if ($element.Type -eq 'Class') { $classes += [ordered]@{ name = $element.Name stereotype = $element.Stereotype notes = $element.Notes } } } $realizations += [ordered]@{ id = $realizationPackage.Name useCase = $useCaseName elements = $classes } } $architecture = $analysisDesign.Packages.GetByName('Architecture Overview') $architecture.Elements.Refresh() $crossCutting = @() for ($e = 0; $e -lt $architecture.Elements.Count; $e++) { $element = $architecture.Elements.GetAt([int]$e) $crossCutting += [ordered]@{ name = $element.Name; notes = $element.Notes } } $realPayload = [ordered]@{ exportedFrom = 'docs/openup/model/skara-brae.eapx (Analysis-Design realization packages)' realizations = $realizations crossCutting = $crossCutting } [System.IO.File]::WriteAllText($realOutPath, ($realPayload | ConvertTo-Json -Depth 8), [System.Text.Encoding]::UTF8) Write-Output "exported: $realOutPath ($($realizations.Count) realizations)" # ---------- lossless XMI backup ---------- try { $project = $repo.GetProjectInterface() $null = $project.ExportPackageXMI($root.PackageGUID, $xmiOutPath, 1, 0) Write-Output "exported: $xmiOutPath (XMI 2.1 backup of model root '$($root.Name)')" } catch { Write-Output "WARNING: XMI export failed ($($_.Exception.Message)); use EA Publish -> XML manually per model/README.md option 2" } $null = $repo.CloseFile() Write-Output 'EXPORT OK - review the exports diff, then commit .eapx + exports/ + scripts/openup/ as one commit' } catch { Write-Output "FAILED: $($_.Exception.ToString())" exit 1 } finally { Get-Process -Name EA -ErrorAction SilentlyContinue | Where-Object { $eaBefore -notcontains $_.Id } | ForEach-Object { Stop-Process -Id $_.Id -Force } }