diff --git a/src/utils/form-io.ts b/src/utils/form-io.ts new file mode 100644 index 0000000..6a990d4 --- /dev/null +++ b/src/utils/form-io.ts @@ -0,0 +1,54 @@ +import { FormDefinition } from '../types'; + +interface FormExport { + version: 1; + forms: FormDefinition[]; +} + +/** + * Serialize forms to a JSON string with a version wrapper. + */ +export function exportForms(forms: FormDefinition[]): string { + const payload: FormExport = { version: 1, forms }; + return JSON.stringify(payload, null, 2); +} + +/** + * Parse a JSON string and extract valid FormDefinitions. + * Generates new UUIDs for each imported form to prevent ID collisions. + * Throws on invalid input. + */ +export function importForms(json: string): FormDefinition[] { + let parsed: unknown; + try { + parsed = JSON.parse(json); + } catch { + throw new Error('Invalid JSON file'); + } + + if ( + typeof parsed !== 'object' || + parsed === null || + !('forms' in parsed) || + !Array.isArray((parsed as FormExport).forms) + ) { + throw new Error('Invalid form format: missing "forms" array'); + } + + const rawForms = (parsed as FormExport).forms; + + for (const form of rawForms) { + if (!form.name || !Array.isArray(form.fields)) { + throw new Error( + 'Invalid form format: each form needs "name" and "fields"', + ); + } + } + + // Generate fresh IDs to avoid collisions + return rawForms.map((form) => ({ + ...form, + id: crypto.randomUUID(), + name: form.name, + })); +}