/** * Document-preserving YAML edits — how faf changes a .faf or .fafm that is * already on disk. * * The file is parsed with yaml's `parseDocument`, the change is made on the * Document through its node APIs (`set` / `setIn` / `delete`), and only the * text of the nodes that changed is rewritten. Every other byte stays as it * was: comments, blank lines, key order, quoting, scalar source text (`1.10`, * `0x1F90`, a 20-digit integer), anchors and aliases, unknown keys, CRLF line * ends and a BOM. * * Safety net: the spliced text is parsed again and must hold the same data as * the changed Document and serialise the same way (comments, styles, anchors; * blank lines aside). If it does not (a shape the splicer does not handle), * faf writes the Document's own serialisation instead — `toString({ * lineWidth: 0 })`, which still keeps comments, anchors, unknown keys and the * source text of every number it did not change. A change that leaves the * data as it was returns the original text untouched — even when that * serialisation would differ — so callers skip the write. */ import { Document, YAMLMap, YAMLSeq, type DocumentOptions, type ParseOptions, type SchemaOptions } from 'yaml'; type YamlOptions = ParseOptions & DocumentOptions & SchemaOptions; /** The result of {@link editYaml}. */ export interface YamlEditResult { /** The new text — the original text when nothing changed. */ text: string; /** False when the change left the document as it was. */ changed: boolean; } /** Parse options for every document faf edits. */ export declare const EDIT_OPTIONS: YamlOptions; /** Parse `src` for editing; a file that is not valid YAML is refused (an * Error whose `cause` is yaml's YAMLParseError, with its line). */ export declare function parseForEdit(src: string, name: string): Document; /** * Parse `text`, let `mutate` change the Document, and return the new text with * every byte outside the changed nodes kept. `name` labels errors (a file that * is not valid YAML is refused — nothing is guessed). When the change leaves * the data as it was (the same values, whatever the nodes or their order), * the original `text` is returned with `changed: false`. */ export declare function editYaml(text: string, mutate: (doc: Document) => void, name?: string): YamlEditResult; /** {@link editYaml}, also saying how the text was made: `spliced` is true when * only the changed nodes were rewritten, false when faf fell back to the * Document's own serialisation (or nothing changed). For tests. */ export declare function editYamlDetailed(text: string, mutate: (doc: Document) => void, name?: string): YamlEditResult & { spliced: boolean; }; /** Deep equality of plain parsed values (mappings compared key by key). */ export declare function sameJs(a: unknown, b: unknown): boolean; /** How {@link applyMapData} treats keys the data does not name. */ export interface ApplyOptions { /** Remove keys of a mapping that the data leaves out (or sets `undefined`). * Default false: a key the data does not mention stays exactly as it is. */ prune?: boolean; /** Leave every alias (`*name`) as written, whatever the data holds there: * it is never expanded or replaced (see {@link keptAliases}). */ keepAliases?: boolean; } /** * Set `node` to hold `value` with the fewest changes: a mapping is updated key * by key, a list item by item (items still there are kept as they are), a * scalar in place (its comment, quoting and position kept). Returns the node * to store — `node` itself, or a new node when the shape changed. */ export declare function applyValue(doc: Document, node: unknown, value: unknown, opts?: ApplyOptions): unknown; /** Make `map` hold `data`: changed keys updated in place, new keys appended in * `data`'s order. Keys `data` leaves out stay, unless `prune` is set. */ export declare function applyMapData(doc: Document, map: YAMLMap, data: Record, opts?: ApplyOptions): void; /** * Merge `data` into `map`, whose parsed value (the file as it was read) is * `before`, writing only the paths where `data` differs from `before`: * - a key whose value in `data` equals its value in `before` is not touched * — its node stays exactly as written, so an alias (`summary: *g`), a * merge key or a comment on it survives even when `data` spells out the * value the alias read as (a stale copy never replaces a live `*alias`); * - a changed mapping is merged key by key the same way; * - any other changed value is set with {@link applyValue}; * - an alias (`stack: *base`) is never replaced or expanded, at any depth: * it stays as written, and a change `data` makes under it is not written * ({@link keptAliases} lists those paths); * - keys `data` leaves out (or sets `undefined`) stay; new keys are appended. * This is how writeFaf applies full .faf data to an existing file. */ export declare function mergeData(doc: Document, map: YAMLMap, before: unknown, data: Record): void; /** An alias faf left as written: where it is (`stack`, `key_files.2`) and * what it says (`*base`). With `kind: 'anchor'` the path holds an anchor an * alias reads (`alias` then says `&name`): `faf auto` would have filled it, * which would change every alias that reads it, so it is left as written. */ export interface KeptAlias { path: string; alias: string; kind?: 'alias' | 'anchor'; } /** The aliases in `doc` where `data` changed the value the file held * (`before`) and the alias does not read as the new value — a change under * an alias that faf did not write, because it never replaces or expands an * alias. A value `data` only repeats (a stale copy of what the alias read * as) is not a change. */ export declare function keptAliases(doc: Document, data: unknown, before: unknown): KeptAlias[]; /** * Put back every alias of `before` that `after` (the same Document, changed) * holds something else in place of: faf never replaces an alias, so that * path keeps the file's `*name` and its change is not written. A key the * change removed stays removed. Returns the aliases put back. */ export declare function restoreAliases(before: Document, after: Document): KeptAlias[]; /** * Put back every node of `before` that carries an anchor an alias reads * (`frontend: &x None` while `ui_library: *x`) and that `after` (the same * Document, changed) holds something else in place of: a fill there would * change the value of every alias that reads it, so faf leaves the node as * written and its change is not written. Returns those paths (`kind: * 'anchor'`, `alias` saying `&name`). */ export declare function restoreAnchors(before: Document, after: Document): KeptAlias[]; /** * Apply the change from `before` to `after` to `node`, touching nothing the * change does not name: for mappings, only keys added, removed or changed * between the two are written — a key in the file that neither side mentions * stays as it is. Returns the node to store. */ export declare function applyChange(doc: Document, node: unknown, before: unknown, after: unknown): unknown; /** The mapping at `path` (created when absent or empty). Throws when something * else is there — faf never replaces a scalar or a list to make room. */ export declare function mapAt(doc: Document, path: readonly string[], name: string): YAMLMap; /** * Apply the change `before` → `after` at `path` (see {@link applyChange}). * The parent mapping is created when absent; `after === undefined` removes the * key. Nothing is touched when the two are equal. */ export declare function changeAt(doc: Document, path: readonly string[], before: unknown, after: unknown, name: string): void; /** The list at `path`, created (as an empty list) when absent or empty. * Throws when something else is there. */ export declare function seqAt(doc: Document, path: readonly string[], name: string): YAMLSeq; export {};