#!/usr/bin/env node /** * Enforce schema/version markers on SF-owned JSON contracts. * * This intentionally does not scan ecosystem configuration files such as * tsconfig.json, package.json, Biome config, or lockfiles. Those files are * versioned by their owning tools. This check covers JSON that SF owns as * runtime data, persisted contracts, or generated artifact templates. */ import { execFileSync } from "node:child_process"; import { readFileSync } from "node:fs"; const REQUIRED_PREFIXES = ["src/resources/extensions/sf/"]; const EXEMPT_SUFFIXES = ["/package.json"]; const VERSION_KEYS = ["schemaVersion", "version"]; function trackedJsonFiles() { try { const out = execFileSync("git", ["ls-files", "*.json"], { encoding: "utf8", stdio: ["ignore", "pipe", "pipe"], }); return out .split("\n") .map((line) => line.trim()) .filter(Boolean); } catch (error) { const message = error instanceof Error ? error.message : String(error); throw new Error(`failed to list tracked JSON files: ${message}`); } } function shouldCheck(path) { return ( REQUIRED_PREFIXES.some((prefix) => path.startsWith(prefix)) && !EXEMPT_SUFFIXES.some((suffix) => path.endsWith(suffix)) ); } function hasOwn(object, key) { return Object.prototype.hasOwnProperty.call(object, key); } function hasVersionMarker(parsed) { if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return false; if (VERSION_KEYS.some((key) => hasOwn(parsed, key))) return true; const meta = parsed._meta; return Boolean( meta && typeof meta === "object" && !Array.isArray(meta) && VERSION_KEYS.some((key) => hasOwn(meta, key)), ); } const failures = []; let checked = 0; for (const path of trackedJsonFiles()) { if (!shouldCheck(path)) continue; checked++; let parsed; try { parsed = JSON.parse(readFileSync(path, "utf8")); } catch (error) { const message = error instanceof Error ? error.message : String(error); failures.push(`${path}: invalid JSON (${message})`); continue; } if (!hasVersionMarker(parsed)) { failures.push( `${path}: missing schemaVersion/version marker (top-level or _meta)`, ); } } if (failures.length > 0) { console.error("Versioned JSON check failed:"); for (const failure of failures) { console.error(` - ${failure}`); } process.exit(1); } console.log(`Versioned JSON check passed (${checked} file${checked === 1 ? "" : "s"}).`);