Files
makelore/electron/opencode/project-template-snapshot.ts
2026-07-29 17:22:35 +08:00

68 lines
2.3 KiB
TypeScript

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<ProjectTemplateSnapshotReadResult> {
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<ProjectTemplateSnapshot> {
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;
}