修改未完成
This commit is contained in:
@@ -1,57 +1,104 @@
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
$root = Split-Path -Parent $PSScriptRoot
|
||||
$documents = @(Get-ChildItem -LiteralPath $root -File -Filter '*.openapi.json')
|
||||
if ($documents.Count -ne 1) { throw 'Exactly one current OpenAPI JSON export is required at the repository root' }
|
||||
$document = Get-Content -Raw -Encoding UTF8 -LiteralPath $documents[0].FullName | ConvertFrom-Json
|
||||
$openApiPath = Join-Path $root 'genealogy-app-openapi.yaml'
|
||||
if (-not (Test-Path -LiteralPath $openApiPath)) {
|
||||
throw 'Current backend OpenAPI export genealogy-app-openapi.yaml is missing at the repository root'
|
||||
}
|
||||
|
||||
$operations = @(
|
||||
foreach ($pathProperty in $document.paths.PSObject.Properties) {
|
||||
foreach ($methodProperty in $pathProperty.Value.PSObject.Properties) {
|
||||
if ($methodProperty.Name -in @('get', 'post', 'put', 'delete', 'patch')) {
|
||||
[PSCustomObject]@{ Path = $pathProperty.Name; Method = $methodProperty.Name }
|
||||
}
|
||||
}
|
||||
$document = Get-Content -Raw -Encoding UTF8 -LiteralPath $openApiPath
|
||||
$operationCount = [regex]::Matches($document, '(?m)^ (?:get|post|put|delete|patch):\s*$').Count
|
||||
if ($operationCount -ne 137) {
|
||||
throw "Current backend OpenAPI operation count drifted: $operationCount"
|
||||
}
|
||||
|
||||
function Get-PathBlock {
|
||||
param([string]$Path)
|
||||
$escapedPath = [regex]::Escape($Path)
|
||||
$match = [regex]::Match($document, "(?ms)^ ${escapedPath}:`r?`n(.*?)(?=^ /|\z)")
|
||||
if (-not $match.Success) { throw "Missing path: $Path" }
|
||||
return $match.Groups[1].Value
|
||||
}
|
||||
|
||||
function Assert-Contains {
|
||||
param([string]$Content, [string]$Expected, [string]$Message)
|
||||
if (-not $Content.Contains($Expected)) { throw $Message }
|
||||
}
|
||||
|
||||
foreach ($path in @(
|
||||
'/genealogy/app/auth/sms/{operationCode}/code',
|
||||
'/genealogy/app/files/resumable/init',
|
||||
'/genealogy/app/files/resumable/chunk',
|
||||
'/genealogy/app/files/resumable/complete',
|
||||
'/genealogy/app/region/children',
|
||||
'/genealogy/app/region/path/{regionCode}',
|
||||
'/genealogy/app/region/search',
|
||||
'/genealogy/app/region/{regionCode}'
|
||||
)) {
|
||||
[void](Get-PathBlock $path)
|
||||
}
|
||||
|
||||
foreach ($retiredPath in @(
|
||||
'/captcha/require',
|
||||
'/captcha/challenge',
|
||||
'/captcha/verify',
|
||||
'/auth/code',
|
||||
'/genealogy/app/auth/sms/code',
|
||||
'/genealogy/app/files/upload',
|
||||
'/genealogy/app/files/reference',
|
||||
'/genealogy/region/children',
|
||||
'/genealogy/region/path/{regionCode}',
|
||||
'/genealogy/region/search',
|
||||
'/genealogy/region/{regionCode}'
|
||||
)) {
|
||||
if ($document -match "(?m)^ $([regex]::Escape($retiredPath)):") {
|
||||
throw "Retired path remains in current backend OpenAPI: $retiredPath"
|
||||
}
|
||||
)
|
||||
if ($operations.Count -ne 149) { throw "Current OpenAPI operation count drifted: $($operations.Count)" }
|
||||
|
||||
function Get-Operation {
|
||||
param([string]$Path, [string]$Method)
|
||||
$pathProperty = $document.paths.PSObject.Properties[$Path]
|
||||
if (-not $pathProperty) { throw "Missing path: $Path" }
|
||||
$operation = $pathProperty.Value.PSObject.Properties[$Method]
|
||||
if (-not $operation) { throw "Missing operation: $Method $Path" }
|
||||
return $operation.Value
|
||||
}
|
||||
|
||||
$videoList = Get-Operation -Path '/genealogy/app/genealogies/{genealogyId}/videos' -Method 'post'
|
||||
if ($videoList.requestBody.content.'application/json'.schema.'$ref' -ne '#/components/schemas/VideoBody') {
|
||||
throw 'Video create must consume VideoBody'
|
||||
$videoPath = Get-PathBlock '/genealogy/app/genealogies/{genealogyId}/videos'
|
||||
Assert-Contains $videoPath "`$ref: '#/components/requestBodies/Video'" 'Video create must consume VideoBody'
|
||||
Assert-Contains $videoPath "`$ref: '#/components/responses/ListResult'" 'Video list remains a generic ListResult until the backend publishes a VideoView DTO'
|
||||
$videoSchema = [regex]::Match($document, "(?ms)^ VideoBody:`r?`n(.*?)(?=^ [A-Za-z][A-Za-z0-9_-]*:|\z)").Value
|
||||
Assert-Contains $videoSchema 'required: [videoTitle, videoOssId]' 'VideoBody required fields drifted'
|
||||
|
||||
foreach ($path in @('/genealogy/app/site/articles', '/genealogy/app/site/pages/{pageKey}')) {
|
||||
$sitePath = Get-PathBlock $path
|
||||
if ($sitePath -match 'VideoView|SiteArticleView|SitePageView') {
|
||||
throw "Site content response DTO changed for $path; review M10 integration"
|
||||
}
|
||||
}
|
||||
$videoBody = $document.components.schemas.VideoBody
|
||||
if ((@($videoBody.required) -join ',') -ne 'videoTitle,videoOssId') {
|
||||
throw 'VideoBody required fields drifted'
|
||||
|
||||
$phoneChangePath = Get-PathBlock '/genealogy/app/auth/phone'
|
||||
Assert-Contains $phoneChangePath "`$ref: '#/components/requestBodies/PhoneChange'" 'Phone change must consume PhoneChangeBody'
|
||||
$phoneChangeSchema = [regex]::Match($document, "(?ms)^ PhoneChangeBody:`r?`n(.*?)(?=^ [A-Za-z][A-Za-z0-9_-]*:|\z)").Value
|
||||
Assert-Contains $phoneChangeSchema 'additionalProperties: false' 'PhoneChangeBody must reject legacy auth payload fields'
|
||||
Assert-Contains $phoneChangeSchema 'required: [phone, smsCode]' 'PhoneChangeBody required fields drifted'
|
||||
|
||||
$apiSource = Get-Content -Raw -Encoding UTF8 -LiteralPath (Join-Path $root 'utils/api.js')
|
||||
foreach ($expected in @(
|
||||
'/genealogy/app/auth/sms/${encodeURIComponent(assertAuthVerificationOperation(operationCode))}/code',
|
||||
'/genealogy/app/region/children',
|
||||
'/genealogy/app/region/path/${encodeURIComponent(normalizeRegionCode(regionCode))}',
|
||||
'/genealogy/app/region/search',
|
||||
'/genealogy/app/region/${encodeURIComponent(normalizeRegionCode(regionCode))}'
|
||||
)) {
|
||||
Assert-Contains $apiSource $expected "Current API adapter missing: $expected"
|
||||
}
|
||||
if ($videoList.responses.'200'.content.'application/json'.schema) {
|
||||
throw 'Video create unexpectedly gained a response DTO; review F10 integration'
|
||||
foreach ($retiredPath in @('/genealogy/app/auth/sms/code', '/genealogy/app/files/upload', '/genealogy/app/files/reference', '/genealogy/region/')) {
|
||||
if ($apiSource.Contains($retiredPath)) { throw "API adapter retains retired backend path: $retiredPath" }
|
||||
}
|
||||
|
||||
$phonePayload = [regex]::Match($apiSource, "(?ms)const normalizePhoneChangePayload = \(payload\) => \{(.*?)^\}").Value
|
||||
Assert-Contains $phonePayload 'return { phone: payload.phone.trim(), smsCode: assertSmsCode(payload.smsCode) }' 'Phone change payload must only contain the documented fields'
|
||||
if ($phonePayload.Contains('authPayload(')) { throw 'Phone change payload must not add clientId or tenantId to PhoneChangeBody' }
|
||||
|
||||
$videoPage = Get-Content -Raw -Encoding UTF8 -LiteralPath (Join-Path $root 'pages/family/f10-video-list.vue')
|
||||
foreach ($token in @('pickAndUploadVideo', 'appApi.createVideo', 'videoTitle', 'videoOssId: receipt.value.ossId')) {
|
||||
if (-not $videoPage.Contains($token)) { throw "F10 video publish contract missing: $token" }
|
||||
Assert-Contains $videoPage $token "F10 video publish contract missing: $token"
|
||||
}
|
||||
foreach ($forbidden in @('v-model="form.videoOssId"', 'v-model="form.status"', 'v-model="form.durationSeconds"')) {
|
||||
if ($videoPage.Contains($forbidden)) { throw "F10 must not expose auto or management field: $forbidden" }
|
||||
}
|
||||
|
||||
foreach ($path in @('/genealogy/app/site/articles', '/genealogy/app/site/pages/{pageKey}')) {
|
||||
$operation = Get-Operation -Path $path -Method 'get'
|
||||
if ($operation.responses.'200'.content.'application/json'.schema) {
|
||||
throw "Site content response DTO changed for $path; review M10 integration"
|
||||
}
|
||||
}
|
||||
|
||||
$auditDocs = @(Get-ChildItem -LiteralPath (Join-Path $root 'docs') -File -Filter '*149*.md')
|
||||
if ($auditDocs.Count -lt 1) { throw 'Current 149 operation audit document is missing' }
|
||||
|
||||
Write-Output 'CURRENT-OPENAPI-INVENTORY-CONTRACT PASS'
|
||||
|
||||
Reference in New Issue
Block a user