import { textIndex, processingPolicy } from "./text-processing.js"; export type VariantSection = { start: number; end: number; text?: string }; export type TextVariant = { source: string; sourceRevision: string; difficulty: string; sections: VariantSection[]; }; /** Canonical ranges never change when an earlier section expands or contracts. * Output offsets are appended in order, so annotations on ready text stay valid. */ export function createVariant(source: string, sourceRevision: string, difficulty: string): TextVariant { const policy = processingPolicy({ chunkChars: 1400 }); return { source, sourceRevision, difficulty, sections: textIndex(source).chunks(policy.chunkChars) }; } export function parseVariant(raw: string): TextVariant | null { const value = JSON.parse(raw); return typeof value.source === "string" && Array.isArray(value.sections) ? value : null; } export function nextSection(variant: TextVariant) { return variant.sections.find((section) => section.text === undefined); } export function applySection(variant: TextVariant, start: number, end: number, text: string) { const section = nextSection(variant); if (!section || section.start !== start || section.end !== end) throw Error("Variant section changed"); if (!text.trim() || text.length > 12000) throw Error("Invalid variant text"); return { ...variant, sections: variant.sections.map((item) => (item === section ? { ...item, text } : item)) }; } export function variantText(variant: TextVariant) { return variant.sections .filter((section) => section.text !== undefined) .map((section) => section.text) .join("\n\n"); }