import { mkdir, readFile, writeFile } from 'node:fs/promises'; import { dirname, join } from 'node:path'; import { validateProjectTemplateSnapshot, type ProjectTemplateSnapshot, } from '../../shared/project-template'; export const PROJECT_TEMPLATE_SNAPSHOT_PATH = '.niancode/project-template.json'; export type ProjectTemplateSnapshotReadResult = | { status: 'missing' } | { status: 'valid'; snapshot: ProjectTemplateSnapshot } | { status: 'invalid'; error: string }; export function getProjectTemplateSnapshotPath(projectPath: string): string { return join(projectPath, '.niancode', 'project-template.json'); } export async function readProjectTemplateSnapshot(projectPath: string): Promise { const snapshotPath = getProjectTemplateSnapshotPath(projectPath); let raw: string; try { raw = await readFile(snapshotPath, 'utf8'); } catch (error) { if ((error as NodeJS.ErrnoException).code === 'ENOENT') { return { status: 'missing' }; } return { status: 'invalid', error: `${PROJECT_TEMPLATE_SNAPSHOT_PATH}: ${String(error)}` }; } let parsed: unknown; try { parsed = JSON.parse(raw); } catch (error) { return { status: 'invalid', error: `${PROJECT_TEMPLATE_SNAPSHOT_PATH}: invalid JSON (${String(error)})` }; } const validation = validateProjectTemplateSnapshot(parsed); if (!validation.ok) { return { status: 'invalid', error: `${PROJECT_TEMPLATE_SNAPSHOT_PATH}: ${validation.error}` }; } return { status: 'valid', snapshot: validation.snapshot }; } export async function writeProjectTemplateSnapshot( projectPath: string, snapshot: ProjectTemplateSnapshot, ): Promise { const validation = validateProjectTemplateSnapshot(snapshot); if (!validation.ok) { throw new Error(validation.error); } const snapshotPath = getProjectTemplateSnapshotPath(projectPath); await mkdir(dirname(snapshotPath), { recursive: true }); try { await writeFile(snapshotPath, `${JSON.stringify(validation.snapshot, null, 2)}\n`, { encoding: 'utf8', flag: 'wx', }); } catch (error) { if ((error as NodeJS.ErrnoException).code === 'EEXIST') { throw new Error(`${PROJECT_TEMPLATE_SNAPSHOT_PATH} already exists and cannot be replaced`, { cause: error }); } throw error; } return validation.snapshot; }