/*
Node-only loader for derived-prices.generated.json (RFC-0767). Reads the file from process.cwd()/src/derived-prices.generated.json and returns null on ENOENT. NOT exported from the semantic barrel — uses node:fs and would pollute client bundles.
- Does not parse or validate the JSON shape — just reads and JSON.parse.
- Does not cache — callers are responsible for calling once and passing the result.
- RFC-0767: relocated loadDerivedPrices from packages/ui to packages/share to break circular dependency. Node-only subpath export.
- RFC-1074: return null for empty {} content — semantically equivalent to "no derived prices".
- RFC-1137: explicit site root for derived-prices loaders (ADR-0089 instance)
*/
import { readFileSync } from "node:fs";
import { join } from "node:path";
import type { DerivedPriceEntry } from "../../semantic/price-marker-resolver.ts";
// RFC-1137 / ADR-0089 (DNA-105): cwd is required — callers must pass the
// site/workpiece root explicitly. The old process.cwd() default resolved
// against the werkstatt repo root inside kernel pipeline steps.
export function loadDerivedPrices(cwd: string): Record | null {
const filePath = join(cwd, "src", "derived-prices.generated.json");
let raw: string;
try {
raw = readFileSync(filePath, "utf-8");
} catch (err: unknown) {
if (err instanceof Error && (err as NodeJS.ErrnoException).code === "ENOENT") {
console.warn(
`[derived-prices] ${filePath} not found — currency-aware price variants will not render. ` +
`Run: pnpm exec werkstatt run derived-prices.materialize --site `,
);
return null;
}
throw err;
}
const parsed = JSON.parse(raw) as Record;
return Object.keys(parsed).length > 0 ? parsed : null;
}