'use strict'; // gitbackup -- shared diff viewer (ticket 23, spec "Не пиши второй // просмотрщик diff"). Before this file existed, history.js was the only // place in the project that rendered a diff into a colored
; ticket 23
// adds a second place that needs one (Overview's "Configuration" card, R124/
// R125's own config_diff indicator, which used to show only the bare
// differs/does-not-differ flag and threw the actual text away). A second,
// separately-typed copy of history.js's own gbDiffLineClass/gbBuildDiffPre
// would be exactly the "третья реализация" ticket 23 explicitly forbids, so
// both call sites use this file instead.
//
// This is deliberately TWO renderers, not one that auto-detects its input,
// because the two rpcd methods that feed them answer genuinely different
// questions in genuinely different formats -- collapsing them into one
// "smart" parser would have to guess which format it was looking at from
// the text alone, and a manifest line that happened to start with "+" or
// "-" (this format's own add/remove marker) would be indistinguishable from
// a coincidence:
//
// unified(text) -- for `diff` (gbrpc_diff, two already-committed shas,
// History's per-commit view): plain `git diff --end-of-options `
// output (usr/sbin/gitbackup's cmd_diff, its two-argument form) -- real
// unified-diff syntax, "diff --git a/X b/X" headers, "@@ ... @@" hunks,
// body lines prefixed ' '/'+'/'-'.
//
// manifest(text) -- for `config_diff` (gbrpc_config_diff, no params,
// Overview's live-drift check): cmd_diff's OTHER, zero-argument form,
// which never calls `git diff` at all -- it walks both manifests'
// entries field by field (_gb_diff_compare/_gb_diff_describe_change,
// usr/sbin/gitbackup) and prints one line per changed path: "+ path
// (type)" (added), "- path (type)" (removed), or "~ path: field
// a->b; ..." (changed) -- the only way this project can show a chmod/
// chown a real `git diff` never sees at all (same blob, same tree entry
// mode class either way; interfaces.md, ticket 17/D03).
//
// No content goes through innerHTML anywhere below -- every line is its own
// text node built through E(), the same "чужие данные никогда не
// становятся разметкой" rule history.js's own diff viewer already followed
// (that file's own header comment, out of this ticket's zone, read before
// writing this).
//
// That holds only because every child below is handed to E() INSIDE AN
// ARRAY, and this file originally got that wrong. LuCI's dom.append()
// branches on the shape of its `children` argument: the Array branch is the
// one that runs each string through document.createTextNode(), while a bare
// string falls all the way through to `node.innerHTML = '' + children` and
// is parsed as markup. `E('span', attrs, line)` therefore rendered a diff
// line AS HTML -- and the text here is `git diff` output, i.e. the contents
// of files fetched from the backup remote, which anyone with push access to
// that repository controls byte for byte. `E('span', attrs, [ line ])` is
// the fix, and the bracket is load-bearing, not punctuation: nothing else
// escapes on the way here (gb_json_esc escapes only what JSON needs, LuCI's
// String.format('%s') does not escape at all, and a LuCI page carries no
// CSP). tests/dom_text_children.test.mjs holds the whole view directory to
// this, so a future call site cannot quietly drop the brackets again.
// css -- the class names both renderers below emit, meant to be spliced
// into each CALLING view's own