import type { Processor } from "./processors.js"; export type ConfigValue = string | number | boolean; export type AnnotatorConfig = Record; export type ConfigField = { key: string; label: string; kind: "color" | "number" | "select" | "toggle" | "text"; default: ConfigValue; options?: { value: string; label: string }[]; min?: number; max?: number; /** False for display-only controls: changing them must reuse inference. */ computation?: boolean; }; export const readingProfiles = [ "light-fast", "light", "quick-fast", "balanced-fast", "balanced", "thorough", "cerebras-light", "cerebras-balanced", ]; export function fieldsFor(processor: Processor): ConfigField[] { return typeof processor.config === "function" ? processor.config() : (processor.config ?? []); } export function computationFields(processor: Processor) { return ( processor.cache?.inputs ?? fieldsFor(processor) .filter((field) => field.computation !== false && field.kind !== "color") .map((field) => field.key) ); } export function normalizeConfig(processor: Processor, raw: string): AnnotatorConfig { if (raw.length > 16000) throw Error("Annotation settings are too large"); const value = JSON.parse(raw); if (!value || typeof value !== "object" || Array.isArray(value)) throw Error("Expected annotation settings"); const fields: ConfigField[] = [ { key: "placement", label: "Label position", kind: "select", default: "above", computation: false, options: [ { value: "above", label: "Above the text" }, { value: "below", label: "Below the text" }, ], }, { key: "fontFamily", label: "Font", kind: "text", default: "" }, { key: "fontSize", label: "Font size", kind: "number", default: 13, min: 6, max: 72 }, { key: "underlinePattern", label: "Underline pattern", kind: "select", default: "solid", computation: false, options: ["solid", "dashed", "squiggly"].map((value) => ({ value, label: value })), }, ...fieldsFor(processor), ]; if (new Set(fields.map((field) => field.key)).size !== fields.length) throw Error("Duplicate annotation control"); for (const key of Object.keys(value)) if (!fields.some((field) => field.key === key)) throw Error("Unknown annotation setting: " + key); const config: AnnotatorConfig = {}; for (const field of fields) { const entry = Object.hasOwn(value, field.key) ? value[field.key] : field.default; if ( typeof entry !== typeof field.default || (typeof entry === "number" && (!Number.isFinite(entry) || entry < (field.min ?? -Infinity) || entry > (field.max ?? Infinity))) || (typeof entry === "string" && (entry.length > 160 || /[\r\n\x00]/.test(entry))) || (field.kind === "color" && (typeof entry !== "string" || !/^#[0-9a-f]{6}$/i.test(entry))) || (field.kind === "select" && !field.options?.some((option) => option.value === entry)) ) throw Error("Invalid annotation setting: " + field.label); config[field.key] = entry; } return config; }