Files
KArtSell.Aegis/docs/Design/kbx-foundation-v36/scripts/generate-screen-recipe-contracts.mjs
T

41 lines
2.9 KiB
JavaScript

import fs from 'node:fs'
import crypto from 'node:crypto'
const source='contracts/screens/kbx.screen-recipes.json'
const scenarioSource='contracts/testing/kbx.test-scenarios.json'
const data=JSON.parse(fs.readFileSync(source,'utf8'))
const scenarios=JSON.parse(fs.readFileSync(scenarioSource,'utf8'))
const scenarioById=new Map(scenarios.scenarios.map(scenario=>[scenario.id,scenario]))
const sha=crypto.createHash('sha256').update(fs.readFileSync(source)).digest('hex')
const scenarioSha=crypto.createHash('sha256').update(fs.readFileSync(scenarioSource)).digest('hex')
const byCode=Object.fromEntries(data.recipes.map(recipe=>[recipe.code,recipe]))
const verification=data.recipes.map(recipe=>{
const canonical=recipe.canonicalScenarioIds.flatMap(id=>scenarioById.has(id)?[scenarioById.get(id)]:[])
const kinds=[...new Set(canonical.map(item=>item.kind))].sort()
const tags=[...new Set(canonical.flatMap(item=>item.tags??[]))].sort()
const evidence=[...new Set(canonical.flatMap(item=>item.evidence??[]))].sort()
const missingScenarioKinds=recipe.testProfile.requiredScenarioKinds.filter(item=>!kinds.includes(item))
const missingTags=recipe.testProfile.requiredTags.filter(item=>!tags.includes(item))
const missingEvidence=recipe.testProfile.requiredEvidence.filter(item=>!evidence.includes(item))
return {
code:recipe.code,
type:recipe.type,
canonicalScenarioIds:recipe.canonicalScenarioIds,
scenarioKinds:kinds,
tags,
evidence,
requiredChecks:recipe.testProfile.requiredChecks,
missingScenarioKinds,
missingTags,
missingEvidence,
complete:!missingScenarioKinds.length&&!missingTags.length&&!missingEvidence.length,
}
})
fs.writeFileSync('generated/screen-recipe-manifest.json',JSON.stringify({schemaVersion:data.schemaVersion,contractVersion:data.contractVersion,sourceSha256:sha,recipes:data.recipes},null,2)+'\n')
fs.writeFileSync('generated/screen-recipe-verification-manifest.json',JSON.stringify({schemaVersion:1,recipeContractVersion:data.contractVersion,scenarioContractVersion:scenarios.contractVersion,recipeSourceSha256:sha,scenarioSourceSha256:scenarioSha,recipes:verification},null,2)+'\n')
const ts=`// generated from ${source}; do not edit.\n// SHA256: ${sha}\nimport type { KbxScreenRecipeDefinition } from '../screen'\n\nexport const kbxScreenRecipeContractVersion=${JSON.stringify(data.contractVersion)} as const\nexport const kbxScreenRecipeCatalog=${JSON.stringify(byCode,null,2)} as const satisfies Record<string,KbxScreenRecipeDefinition>\nexport const kbxScreenRecipeVerificationCatalog=${JSON.stringify(Object.fromEntries(verification.map(item=>[item.code,item])),null,2)} as const\n`
fs.writeFileSync('packages/kbx-contracts/src/generated/screenRecipeCatalog.ts',ts)
console.log(`screen recipe contracts generated: recipes=${data.recipes.length}, verification=${verification.filter(item=>item.complete).length}/${verification.length}`)