import type { ComputeAppConfig, ComputeConfig } from "./types.ts"; /** * Renders a `prisma.compute.ts` source file for a config — the scaffolding * counterpart of `loadComputeConfig`. Output round-trips through * `normalizeComputeConfig` and is stable for committing to a repository. */ export function serializeComputeConfig( config: ComputeConfig, options?: { /** Import specifier for the typed helper. Defaults to this SDK. */ importFrom?: string; }, ): string { const importFrom = options?.importFrom ?? "@prisma/compute-sdk/config"; const body = "app" in config && config.app !== undefined ? `{\n app: ${renderValue(config.app, 1)},\n}` : `{\n apps: ${renderValue((config as { apps: Record }).apps, 1)},\n}`; return [ `import { defineComputeConfig } from ${JSON.stringify(importFrom)};`, "", `export default defineComputeConfig(${body});`, "", ].join("\n"); } const IDENTIFIER_KEY = /^[A-Za-z_$][A-Za-z0-9_$]*$/; function renderValue(value: unknown, depth: number): string { if (value === null) { return "null"; } switch (typeof value) { case "string": return JSON.stringify(value); case "number": case "boolean": return String(value); case "object": break; default: throw new Error( `Cannot serialize a ${typeof value} value in a compute config.`, ); } if (Array.isArray(value)) { return `[${value.map((entry) => renderValue(entry, depth)).join(", ")}]`; } const entries = Object.entries(value as Record).filter( ([, entry]) => entry !== undefined, ); if (entries.length === 0) { return "{}"; } const indent = " ".repeat(depth + 1); const closingIndent = " ".repeat(depth); const rendered = entries.map(([key, entry]) => { // "__proto__" needs a computed key: in an object literal both the bare // and the quoted form set the prototype instead of defining a property. const renderedKey = key === "__proto__" ? '["__proto__"]' : IDENTIFIER_KEY.test(key) ? key : JSON.stringify(key); return `${indent}${renderedKey}: ${renderValue(entry, depth + 1)},`; }); return `{\n${rendered.join("\n")}\n${closingIndent}}`; }