import { readdirSync, readFileSync } from 'node:fs'; import { join, relative, sep } from 'node:path'; // HoneyBatch.amount is the running rest of the movement book (spec 7.7): only // HoneyBatchLedgerService writes it. A second writer would break the // invariant amount = initialAmount + sum(quantity) / 1000. // // The regexes see an `amount` inside the call itself. A spread such as // `data: { ...dto }` is invisible to them; honey-batches.service.spec.ts // covers that case. const SRC = join(__dirname, '..'); const LEDGER = 'src/honey-batches/honey-batch-ledger.service.ts'; function productionSources(dir: string): string[] { return readdirSync(dir, { withFileTypes: true }).flatMap((entry) => { const path = join(dir, entry.name); if (entry.isDirectory()) { return productionSources(path); } return entry.name.endsWith('.ts') && !entry.name.endsWith('.spec.ts') ? [path] : []; }); } function writersOf(...patterns: RegExp[]): string[] { return productionSources(SRC) .filter((file) => { const source = readFileSync(file, 'utf8'); return patterns.some((pattern) => pattern.test(source)); }) .map((file) => `src/${relative(SRC, file).split(sep).join('/')}`) .sort(); } describe('honey batch amount writes', () => { it('honey batch amount is written only by the ledger', () => expect( writersOf( /honeyBatch\.(update|updateMany|upsert)\([^)]*amount/s, /UPDATE "HoneyBatch"[^;]*"amount"/, ), ).toEqual([LEDGER])); it('the guard sees a write: the ledger itself is found', () => expect(writersOf(/honeyBatch\.update\(\{[^)]*data: \{ amount/s)).toContain( LEDGER, )); });