diff --git a/scripts/generator-freshness-contract.cjs b/scripts/generator-freshness-contract.cjs new file mode 100644 index 000000000..1564830c7 --- /dev/null +++ b/scripts/generator-freshness-contract.cjs @@ -0,0 +1,31 @@ +'use strict'; + +const GENERATOR_FRESHNESS_REASON = Object.freeze({ + FRESH: 'fresh', + STALE: 'stale', + MISSING_SOURCE: 'missing_source', + MISSING_GENERATED: 'missing_generated', +}); + +/** + * Compare source and generated artifacts by content hash-equivalence contract. + * @param {{source?:string, generated?:string}} input + * @returns {{ok:boolean, reason:string}} + */ +function evaluateGeneratorFreshness(input) { + const source = input?.source; + const generated = input?.generated; + + if (typeof source !== 'string') { + return { ok: false, reason: GENERATOR_FRESHNESS_REASON.MISSING_SOURCE }; + } + if (typeof generated !== 'string') { + return { ok: false, reason: GENERATOR_FRESHNESS_REASON.MISSING_GENERATED }; + } + if (source === generated) { + return { ok: true, reason: GENERATOR_FRESHNESS_REASON.FRESH }; + } + return { ok: false, reason: GENERATOR_FRESHNESS_REASON.STALE }; +} + +module.exports = { GENERATOR_FRESHNESS_REASON, evaluateGeneratorFreshness }; diff --git a/tests/generator-freshness-contract.test.cjs b/tests/generator-freshness-contract.test.cjs new file mode 100644 index 000000000..1af36fe97 --- /dev/null +++ b/tests/generator-freshness-contract.test.cjs @@ -0,0 +1,29 @@ +const { test, describe } = require('node:test'); +const assert = require('node:assert/strict'); + +const { + GENERATOR_FRESHNESS_REASON, + evaluateGeneratorFreshness, +} = require('../scripts/generator-freshness-contract.cjs'); + +describe('generator freshness contract module', () => { + test('fresh when source and generated match exactly', () => { + const out = evaluateGeneratorFreshness({ source: 'abc', generated: 'abc' }); + assert.deepStrictEqual(out, { ok: true, reason: GENERATOR_FRESHNESS_REASON.FRESH }); + }); + + test('stale when source and generated differ', () => { + const out = evaluateGeneratorFreshness({ source: 'abc', generated: 'abd' }); + assert.deepStrictEqual(out, { ok: false, reason: GENERATOR_FRESHNESS_REASON.STALE }); + }); + + test('missing_source when source omitted', () => { + const out = evaluateGeneratorFreshness({ generated: 'abc' }); + assert.deepStrictEqual(out, { ok: false, reason: GENERATOR_FRESHNESS_REASON.MISSING_SOURCE }); + }); + + test('missing_generated when generated omitted', () => { + const out = evaluateGeneratorFreshness({ source: 'abc' }); + assert.deepStrictEqual(out, { ok: false, reason: GENERATOR_FRESHNESS_REASON.MISSING_GENERATED }); + }); +});