import fs from 'node:fs' import crypto from 'node:crypto' const read = p => JSON.parse(fs.readFileSync(p, 'utf8')) const scenarioPath = 'contracts/testing/kbx.test-scenarios.json' const fixturePath = 'contracts/testing/kbx.test-fixtures.json' const scenarios = read(scenarioPath) const fixtures = read(fixturePath) const sha = p => crypto.createHash('sha256').update(fs.readFileSync(p)).digest('hex') const scenarioSha = sha(scenarioPath) const fixtureSha = sha(fixturePath) const manifest = { schemaVersion: scenarios.schemaVersion, contractVersion: scenarios.contractVersion, sourceSha256: scenarioSha, fixtureVersion: fixtures.fixtureVersion, fixtureSourceSha256: fixtureSha, fixedReferenceClock: scenarios.principles.fixedReferenceClock, scenarios: scenarios.scenarios.map(s => ({ id: s.id, title: s.title, screenId: s.screenId, kind: s.kind, tags: s.tags, fixtureSets: s.fixtureSets, requiredPermissions: s.requiredPermissions, apiOperations: s.apiOperations, isolation: s.isolation, assertionCount: s.assertions.length, evidence: s.evidence, })), } fs.writeFileSync('generated/test-scenario-manifest.json', JSON.stringify(manifest, null, 2) + '\n') const fixtureManifest = { schemaVersion: fixtures.schemaVersion, fixtureVersion: fixtures.fixtureVersion, sourceSha256: fixtureSha, syntheticOnly: fixtures.syntheticOnly, fixedReferenceClock: fixtures.fixedReferenceClock, testTenant: fixtures.testTenant, fixtureSets: fixtures.fixtureSets, refCount: Object.keys(fixtures.refs ?? {}).length, } fs.writeFileSync('generated/test-fixture-manifest.json', JSON.stringify(fixtureManifest, null, 2) + '\n') const scenarioCatalog = Object.fromEntries(scenarios.scenarios.map(s => [s.id, s])) const fixtureSetCatalog = Object.fromEntries(fixtures.fixtureSets.map(s => [s.id, s])) const ts = `// generated from KBX test contracts; do not edit.\n` + `// Scenario SHA256: ${scenarioSha}\n// Fixture SHA256: ${fixtureSha}\n\n` + `import type { KbxTestScenarioDefinition, KbxTestFixtureSetDefinition } from '../testing'\n\n` + `export const kbxTestScenarioContractVersion = ${JSON.stringify(scenarios.contractVersion)} as const\n` + `export const kbxTestFixtureVersion = ${JSON.stringify(fixtures.fixtureVersion)} as const\n` + `export const kbxTestReferenceClock = ${JSON.stringify(scenarios.principles.fixedReferenceClock)} as const\n\n` + `export const kbxTestScenarioCatalog = ${JSON.stringify(scenarioCatalog, null, 2)} as const satisfies Record\n\n` + `export const kbxTestFixtureSetCatalog = ${JSON.stringify(fixtureSetCatalog, null, 2)} as const satisfies Record\n` + `export const kbxTestFixtureRefs = ${JSON.stringify(fixtures.refs, null, 2)} as const\n` fs.writeFileSync('packages/kbx-contracts/src/generated/testScenarioCatalog.ts', ts) const csString = s => `"${String(s).replaceAll('\\', '\\\\').replaceAll('"', '\\"')}"` const csList = a => `new[] { ${(a ?? []).map(csString).join(', ')} }` const rows = scenarios.scenarios.map(s => ` new(${csString(s.id)}, ${csString(s.title)}, ${csString(s.screenId)}, ${csString(s.kind)}, ${csList(s.tags)}, ${csList(s.fixtureSets)}, ${csList(s.requiredPermissions)}, ${csList(s.apiOperations)}, ${csString(s.isolation)})` ).join(',\n') const cs = `// GENERATED. DO NOT EDIT.\n// Scenario SHA256: ${scenarioSha}\n// Fixture SHA256: ${fixtureSha}\nnamespace Shared.Testing.Generated;\n\npublic sealed record KbxTestScenarioContract(\n string Id, string Title, string ScreenId, string Kind,\n IReadOnlyList Tags, IReadOnlyList FixtureSets,\n IReadOnlyList RequiredPermissions, IReadOnlyList ApiOperations,\n string Isolation);\n\npublic static class KbxTestScenarioCatalog\n{\n public const string ContractVersion = ${csString(scenarios.contractVersion)};\n public const string FixtureVersion = ${csString(fixtures.fixtureVersion)};\n public const string ReferenceClock = ${csString(scenarios.principles.fixedReferenceClock)};\n public static IReadOnlyList All { get; } = new KbxTestScenarioContract[]\n {\n${rows}\n };\n}\n` fs.writeFileSync('backend/Shared/Testing/Generated/KbxTestScenarioCatalog.g.cs', cs) console.log(`test contracts generated: scenarios=${scenarios.scenarios.length}, fixtureSets=${fixtures.fixtureSets.length}, refs=${Object.keys(fixtures.refs ?? {}).length}`)