All files cache-key.ts

94.11% Statements 16/17
88.88% Branches 8/9
100% Functions 2/2
94.11% Lines 16/17

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 391x                                     1x 22x 22x   22x 22x 17x 17x 7x 1x 1x 4x 4x 4x 7x       22x  
/**
 * Go cacheKey implementation.
 *
 * Produces `go-${goSumHash || goModHash || 'no-config'}`.
 *
 * Prefers go.sum over go.mod when both are present — go.sum holds the
 * resolved dependency tree (with hashes), so changing a dep version
 * reliably flips the key. go.mod (the manifest) is the fallback when
 * go.sum isn't checked in (rare; Go conventionally commits it).
 *
 * Per contract invariant I-6: pure function of `(config content)`.
 * Per I-8: emits `go-`, distinct from `rs-` and `py-`.
 */
 
import { createHash } from 'node:crypto';
import { existsSync, readFileSync } from 'node:fs';
 
import type { CacheKeyInput } from '@opensip-tools/graph';
 
export function cacheKey(input: CacheKeyInput): string {
  return `go-${hashConfig(input.configPathAbs)}`;
}
 
function hashConfig(configPathAbs: string | undefined): string {
  if (configPathAbs === undefined || configPathAbs.length === 0) {
    return 'no-config';
  }
  if (!existsSync(configPathAbs)) {
    return `missing:${configPathAbs}`;
  }
  try {
    const content = readFileSync(configPathAbs, 'utf8');
    return createHash('sha256').update(content).digest('hex').slice(0, 16);
  } catch {
    /* v8 ignore next */
    return `unreadable:${configPathAbs}`;
  }
}