tee

command
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 28, 2026 License: BSD-3-Clause Imports: 6 Imported by: 0

Documentation

Overview

Command tee streams a document to two destinations at once - one rewritten, one exactly as it arrived - from a single read of the input, and reports how far apart they ran.

$ tee -rewritten out.html -verbatim raw.html page.html
7400 bytes in, 10400 out rewritten, 7400 out verbatim
  widest gap        12 bytes, with the verbatim copy ahead
  held by           a start tag no selector had ruled out
  sink calls        4400 rewritten, 200 verbatim

The verbatim copy is the input, so there is nothing to compute for it: tee the reader and give one branch to the rewriter. What is worth knowing is the gap, because it is the only view from outside of what the rewriter is holding.

A start tag is held until every selector has been ruled out

The verbatim copy runs ahead by whatever the rewriter has buffered, and that is bounded by one start tag rather than by the document. Which tag depends on the selectors, and not on whether any handler ran. Feeding a 5513-byte document one byte at a time and watching the widest gap:

document                            selector             widest gap
<div data-x="1" … >x</div>          none                          5
                                    a[href]                       5
                                    span[data-x]                  5
                                    div[data-x]                5505
                                    div[data-absent]           5505
                                    div.absent                 5505
                                    div#absent                 5505
                                    [data-absent]              5505
                                    *                          5505

A tag name rules a selector out at the name and the rest of the tag streams. An attribute, a class or an id cannot be ruled out until the tag ends, so the tag is held whether it matches or not - div[data-absent] holds as much as div[data-x] does. A selector with no tag-name component holds every tag.

So the bound is the longest start tag whose name some selector does not exclude. Ordinary markup gives a gap of a few bytes; a tag with five hundred attributes gives five thousand, and only if a selector could still be interested in it. Text is never held: a 10 KB text node ran a gap of three bytes with a text handler registered and without one.

The one way to make the gap the size of the document is to do it yourself - accumulating a text node to lolhtml.TextChunk.IsLastInTextNode and removing the chunks along the way held 10003 of 10007 bytes. That is the caller's buffer, not the rewriter's, and it is worth knowing which is which when a memory figure looks wrong.

The two destinations fail differently

The verbatim copy is written first, so a rewrite that fails has already put bytes in it. There is no ordering that avoids this: whichever is written first is ahead when the other breaks. What a caller can do is know which, and this reports the counts so a partial pair is recognisable rather than surprising.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL