import type { WorkbookSheet } from './workbook-xlsx.js'; /** * Turning an edited workbook back into operations (#355, ADR 0127). * * The workbook carries its own ancestor. `~Baseline` is a copy of the working * rows exactly as exported, never edited and never updated, and it is what * makes this a THREE-way merge rather than an overwrite: without it, "this * cell differs from the model" cannot distinguish *the author changed it* from * *the repository moved underneath since the workbook was made*, and the * second is silently clobbered. * * So the comparison is run twice: * * working vs baseline -> what the author did * current vs baseline -> what the repository did since * * A cell both changed is a conflict and is refused, naming the field and both * values. Everything else merges. Nothing is written for a conflict, because * `apply` is atomic and a half-applied workbook is worse than a refused one. */ /** A sheet reduced to rows keyed by the id in column A. */ export interface KeyedSheet { readonly header: readonly string[]; readonly rows: ReadonlyMap; } export interface CellChange { readonly sheet: string; readonly id: string; readonly column: string; readonly from: string; readonly to: string; } export interface Conflict extends CellChange { /** What the repository moved the same field to since the export. */ readonly theirs: string; } export interface MergeReport { readonly changes: readonly CellChange[]; readonly added: readonly { readonly sheet: string; readonly id: string; }[]; readonly conflicts: readonly Conflict[]; /** * Rows the workbook no longer has. Reported, never actioned: a row deleted * by accident in a spreadsheet has no symptom, and deletion is not a thing * this import does. */ readonly missing: readonly { readonly sheet: string; readonly id: string; }[]; } /** A column whose value is derived for readability and ignored on the way back. */ export declare const isDerivedColumn: (label: string) => boolean; export declare const keySheet: (rows: readonly (readonly string[])[]) => KeyedSheet; /** * The baseline sheet holds every working row prefixed by its sheet name, so * one hidden sheet can carry them all. This puts them back. */ export declare const baselineSheets: (rows: readonly (readonly string[])[]) => ReadonlyMap; /** * Three-way merge over one sheet. * * `current` is the sheet as it would be exported from the model right now, so * drift is measured in exactly the terms the author edited in rather than * against the YAML. */ export declare const mergeSheet: (sheet: string, working: KeyedSheet, baseline: KeyedSheet, current: KeyedSheet) => MergeReport; /** * Merge every working sheet the workbook and the model share. * * A sheet present in one and not the other is skipped rather than guessed at: * the machinery sheets are not working data, and a sheet the model no longer * produces is not something an import should invent operations for. */ export declare const mergeWorkbook: (working: ReadonlyMap, baseline: ReadonlyMap, current: readonly WorkbookSheet[]) => MergeReport;