@beltype/cicero 0.1.6 → 0.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/seam/index.js +3 -1
- package/dist/src/capture.d.ts +22 -2
- package/dist/src/capture.js +164 -70
- package/dist/src/chase.js +2 -0
- package/dist/src/data-beltype.d.ts +2 -2
- package/dist/src/data-beltype.js +4 -4
- package/dist/src/document-state.d.ts +49 -2
- package/dist/src/document-state.js +93 -7
- package/dist/src/dressing.d.ts +5 -1
- package/dist/src/dressing.js +23 -16
- package/dist/src/driver.d.ts +10 -3
- package/dist/src/driver.js +118 -40
- package/dist/src/fragmentation.d.ts +1 -1
- package/dist/src/fragmentation.js +1 -1
- package/dist/src/fragments.d.ts +2 -2
- package/dist/src/fragments.js +49 -10
- package/dist/src/gauge.d.ts +4 -0
- package/dist/src/gauge.js +14 -2
- package/dist/src/hyphen-patterns/en-us.d.ts +1 -0
- package/dist/src/hyphen-patterns/en-us.js +2 -0
- package/dist/src/hyphen-patterns/it.d.ts +21 -0
- package/dist/src/hyphen-patterns/it.js +52 -0
- package/dist/src/hyphenate.d.ts +5 -2
- package/dist/src/hyphenate.js +14 -6
- package/dist/src/measure.d.ts +5 -3
- package/dist/src/measure.js +15 -10
- package/dist/src/reads.d.ts +3 -2
- package/dist/src/reads.js +27 -5
- package/dist/src/stonehand.js +41 -14
- package/dist/src/word-space.d.ts +8 -0
- package/dist/src/word-space.js +15 -0
- package/package.json +1 -1
|
@@ -20,5 +20,5 @@ export { assertRenderConditions, awaitCloneImages, awaitFonts, createMeasureCont
|
|
|
20
20
|
export { divides, elAt, extensionPx, indexBlocks, normalizePath, pageContaining, pageIntervals, pathOf, placeAt } from './positions.ts';
|
|
21
21
|
export { present, presentation } from './presenters.ts';
|
|
22
22
|
export { cssString, findPageSites, settleReads } from './reads.ts';
|
|
23
|
-
export { adjudicate, fitsPage, isOutOfFlow, neverCutInside, processionBottoms, reachesBelowTheEdge } from './stonehand.ts';
|
|
23
|
+
export { adjudicate, firstBelowTheEdge, fitsPage, isOutOfFlow, neverCutInside, processionBottoms, reachesBelowTheEdge } from './stonehand.ts';
|
|
24
24
|
export { BREAKING_SPACE, copyOf, isFixedBox, isInlineBox, isLineBreak, noteSource } from './word-space.ts';
|
|
@@ -19,5 +19,5 @@ export { assertRenderConditions, awaitCloneImages, awaitFonts, createMeasureCont
|
|
|
19
19
|
export { divides, elAt, extensionPx, indexBlocks, normalizePath, pageContaining, pageIntervals, pathOf, placeAt } from './positions.js';
|
|
20
20
|
export { present, presentation } from './presenters.js';
|
|
21
21
|
export { cssString, findPageSites, settleReads } from './reads.js';
|
|
22
|
-
export { adjudicate, fitsPage, isOutOfFlow, neverCutInside, processionBottoms, reachesBelowTheEdge } from './stonehand.js';
|
|
22
|
+
export { adjudicate, firstBelowTheEdge, fitsPage, isOutOfFlow, neverCutInside, processionBottoms, reachesBelowTheEdge } from './stonehand.js';
|
|
23
23
|
export { BREAKING_SPACE, copyOf, isFixedBox, isInlineBox, isLineBreak, noteSource } from './word-space.js';
|
package/dist/src/fragments.d.ts
CHANGED
|
@@ -96,10 +96,10 @@ export declare function mayRepeat(src: Element): boolean;
|
|
|
96
96
|
* **`keep` is the first fragment's door into the same surgery** (*the first fragment is constructed*, 2026-09-15). A shell continues a box whose own content closed on the page before, so page one wants everything after that box gone and the box itself standing — the one difference from the grab's reading, where the boundary box is what resumes. With `keep`, the boundary element stays and is dressed as a fragment that ends there, which it is.
|
|
97
97
|
*
|
|
98
98
|
* @param clone - the top-level block's clone, already hinted and already consumed to the cursor.
|
|
99
|
-
* @param el - the boundary
|
|
99
|
+
* @param el - the boundary node, addressed in the clone's own coordinates: an element, or the first node of a run of lines, which has no element (*the anonymous box is in the procession*).
|
|
100
100
|
* @param opts - `keep`: the boundary element stays in the fragment (and is dressed), rather than leaving with its successors. `hollow`: what leaves is kept hollow (`putAway`).
|
|
101
101
|
*/
|
|
102
|
-
export declare function truncateFrom(clone: Element, el:
|
|
102
|
+
export declare function truncateFrom(clone: Element, el: ChildNode, { keep, hollow }?: {
|
|
103
103
|
keep?: boolean;
|
|
104
104
|
hollow?: boolean;
|
|
105
105
|
}): Element;
|
package/dist/src/fragments.js
CHANGED
|
@@ -317,7 +317,7 @@ function liftRepeatedHeader(group) {
|
|
|
317
317
|
* **`keep` is the first fragment's door into the same surgery** (*the first fragment is constructed*, 2026-09-15). A shell continues a box whose own content closed on the page before, so page one wants everything after that box gone and the box itself standing — the one difference from the grab's reading, where the boundary box is what resumes. With `keep`, the boundary element stays and is dressed as a fragment that ends there, which it is.
|
|
318
318
|
*
|
|
319
319
|
* @param clone - the top-level block's clone, already hinted and already consumed to the cursor.
|
|
320
|
-
* @param el - the boundary
|
|
320
|
+
* @param el - the boundary node, addressed in the clone's own coordinates: an element, or the first node of a run of lines, which has no element (*the anonymous box is in the procession*).
|
|
321
321
|
* @param opts - `keep`: the boundary element stays in the fragment (and is dressed), rather than leaving with its successors. `hollow`: what leaves is kept hollow (`putAway`).
|
|
322
322
|
*/
|
|
323
323
|
export function truncateFrom(clone, el, { keep = false, hollow = false } = {}) {
|
|
@@ -377,22 +377,59 @@ function charRanges(word, from, to) {
|
|
|
377
377
|
}
|
|
378
378
|
return out;
|
|
379
379
|
}
|
|
380
|
+
/** Whether the whitespace of a text node stands in its layout (css-text-4 §4.1): where it collapses it is nothing at a line's edge, and where it is preserved each newline draws a line. */
|
|
381
|
+
const preservesSpace = (t) => !!t.parentElement && /^(pre|pre-wrap|pre-line|break-spaces)$/.test(sourceStyle(t.parentElement)?.whiteSpace ?? '');
|
|
382
|
+
/** Take a stretch of a cut's whitespace out of the fragment: leave it where it collapses, so layout reads the data exactly as before, and remove it where it is preserved, or a continuation opens on the empty lines of every line cut away. Either way the record says it is not shown. */
|
|
383
|
+
function dropSpace(t, from, to) {
|
|
384
|
+
if (to <= from)
|
|
385
|
+
return;
|
|
386
|
+
if (preservesSpace(t))
|
|
387
|
+
cutRanges(t, [{ start: from, end: to }]);
|
|
388
|
+
else
|
|
389
|
+
leaveOut(t, from, to);
|
|
390
|
+
}
|
|
380
391
|
/**
|
|
381
|
-
*
|
|
392
|
+
* The indentation of the line a resume word opens: the whitespace before it back to a newline, in characters. Read before the words before it go, because only they tell the space that opens a line from the space that followed a word. A cut at a soft wrap has no newline in that gap and no indentation, the space hanging at the end of the line before; a line after a `<br>` looks the same and loses its indentation at the top of a page.
|
|
393
|
+
*/
|
|
394
|
+
function indentationBefore(clone, node, start) {
|
|
395
|
+
let text = '';
|
|
396
|
+
for (const t of textsIn(clone)) {
|
|
397
|
+
if (t === node) {
|
|
398
|
+
text += t.data.slice(0, start);
|
|
399
|
+
break;
|
|
400
|
+
}
|
|
401
|
+
text += t.data;
|
|
402
|
+
}
|
|
403
|
+
let i = text.length;
|
|
404
|
+
while (i > 0 && BREAKING_SPACE.test(text[i - 1]))
|
|
405
|
+
i--;
|
|
406
|
+
const newline = text.lastIndexOf('\n');
|
|
407
|
+
return newline < i ? 0 : text.length - newline - 1;
|
|
408
|
+
}
|
|
409
|
+
/**
|
|
410
|
+
* Say that everything before the resume point is held and not shown (*the engine names the source point*, 2026-10-13). Consuming blanks the words and leaves the whitespace between them, so a continuation's data still begins with the spaces of every word cut away; those are the source's characters and no part of the interval, and so are the whitespace before the first kept word and every text node that stands wholly before it. Where the whitespace collapses these are records only, and where it is preserved they leave the data (`dropSpace`), all but the indentation of the line the page opens on.
|
|
382
411
|
*
|
|
383
412
|
* @param resume - the node holding the first kept character, or null when nothing is kept.
|
|
413
|
+
* @param indent - the characters immediately before it to keep, from {@link indentationBefore}.
|
|
384
414
|
*/
|
|
385
|
-
function leaveOutBefore(clone, resume) {
|
|
415
|
+
function leaveOutBefore(clone, resume, indent) {
|
|
416
|
+
const lead = [];
|
|
386
417
|
for (const t of textsIn(clone)) {
|
|
387
418
|
if (t === resume)
|
|
388
419
|
break;
|
|
389
|
-
|
|
420
|
+
lead.push({ node: t, end: t.data.length });
|
|
390
421
|
}
|
|
391
422
|
if (resume) {
|
|
392
423
|
let at = 0;
|
|
393
424
|
while (at < resume.data.length && BREAKING_SPACE.test(resume.data[at]))
|
|
394
425
|
at++;
|
|
395
|
-
|
|
426
|
+
lead.push({ node: resume, end: at });
|
|
427
|
+
}
|
|
428
|
+
let left = indent;
|
|
429
|
+
for (const { node, end } of lead.reverse()) {
|
|
430
|
+
const kept = preservesSpace(node) ? Math.min(left, end) : 0;
|
|
431
|
+
left -= kept;
|
|
432
|
+
dropSpace(node, 0, end - kept);
|
|
396
433
|
}
|
|
397
434
|
}
|
|
398
435
|
/** The mirror: everything after the last kept character is held and not shown.@param keep - the node holding the last kept character. */
|
|
@@ -400,14 +437,14 @@ function leaveOutAfter(clone, keep) {
|
|
|
400
437
|
let end = keep.data.length;
|
|
401
438
|
while (end > 0 && BREAKING_SPACE.test(keep.data[end - 1]))
|
|
402
439
|
end--;
|
|
403
|
-
leaveOut(keep, end, keep.data.length);
|
|
404
440
|
let after = false;
|
|
405
|
-
for (const t of textsIn(clone)) {
|
|
441
|
+
for (const t of [...textsIn(clone)]) {
|
|
406
442
|
if (after)
|
|
407
|
-
|
|
443
|
+
dropSpace(t, 0, t.data.length);
|
|
408
444
|
else if (t === keep)
|
|
409
445
|
after = true;
|
|
410
446
|
}
|
|
447
|
+
dropSpace(keep, end, keep.data.length);
|
|
411
448
|
}
|
|
412
449
|
/** The text nodes under an element, in document order — by `childNodes`, as `joinedWords` reads, so the DOM-free suites' trees serve. */
|
|
413
450
|
function* textsIn(el) {
|
|
@@ -426,7 +463,9 @@ function consumeLeadingWords(clone, n, char = 0, hollow = false) {
|
|
|
426
463
|
// A resume inside word n (*a line inside a word is a break point*, 2026-09-23): its first `char` characters were shown on the page before, and go with the words before it. The page resumes at the part holding the first character left.
|
|
427
464
|
const inside = char > 0 && n < words.length ? charRanges(words[n], 0, char) : [];
|
|
428
465
|
const resumeWord = words[Math.min(n, words.length - 1)];
|
|
429
|
-
const
|
|
466
|
+
const resumePart = n < words.length ? partAt(resumeWord, char) ?? resumeWord.parts[0] : null;
|
|
467
|
+
const resumeNode = resumePart?.node ?? null;
|
|
468
|
+
const indent = resumePart && char === 0 ? indentationBefore(clone, resumePart.node, resumePart.start) : 0;
|
|
430
469
|
// Blank the consumed words' exact character ranges, one pass a node (`word-space.js`' `cutRanges`, which records what went).
|
|
431
470
|
const perNode = new Map();
|
|
432
471
|
for (const part of [...words.slice(0, n).flatMap((w) => w.parts), ...inside]) {
|
|
@@ -436,7 +475,7 @@ function consumeLeadingWords(clone, n, char = 0, hollow = false) {
|
|
|
436
475
|
}
|
|
437
476
|
for (const [node, ranges] of perNode)
|
|
438
477
|
cutRanges(node, ranges);
|
|
439
|
-
leaveOutBefore(clone, resumeNode);
|
|
478
|
+
leaveOutBefore(clone, resumeNode, indent);
|
|
440
479
|
// Structural pass: an element with no remaining words, standing entirely before the resume point, is spent — its edges adjoin the cut (§5.2) and it leaves the fragment.
|
|
441
480
|
const spent = [];
|
|
442
481
|
(function walk(el) {
|
package/dist/src/gauge.d.ts
CHANGED
|
@@ -45,6 +45,8 @@ export type Box = {
|
|
|
45
45
|
anonymous?: boolean;
|
|
46
46
|
/** A table's footer group written before its rows (`footerBeforeRows`), moved to the end of the table's procession, where §17.2 lays it out. */
|
|
47
47
|
laidOutLast?: boolean;
|
|
48
|
+
/** A table's header group written after its rows (`headerAfterRows`), moved to the front of the table's procession, where §17.2 lays it out. */
|
|
49
|
+
laidOutFirst?: boolean;
|
|
48
50
|
};
|
|
49
51
|
/** One line box, recovered arithmetically from the rects clustered onto it and the line-heights they are set on (`computeLines`). */
|
|
50
52
|
export type LineBox = {
|
|
@@ -95,6 +97,8 @@ export type Tracks = {
|
|
|
95
97
|
};
|
|
96
98
|
/** The sealed report {@link takeReport} hands back. */
|
|
97
99
|
export type MeasureReport = ReturnType<typeof takeReport>;
|
|
100
|
+
/** A `display` whose inline content CSS 2.1 §9.2.1.1 wraps in anonymous block boxes — a block container's. A flex or grid container makes a run an anonymous item and a table an anonymous cell, which are other boxes and other questions. */
|
|
101
|
+
export declare const holdsAnonymousBlocks: (display: string) => boolean;
|
|
98
102
|
/**
|
|
99
103
|
* Read one settled layout into an immutable snapshot — obtaining it seals the mutation phase (*render-identical conditions*, I5, by type).
|
|
100
104
|
*
|
package/dist/src/gauge.js
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* @packageDocumentation
|
|
16
16
|
*/
|
|
17
17
|
import { BREAK, selectorOf } from './data-beltype.js';
|
|
18
|
-
import { blockChildrenOf, footerBeforeRows, isAtom, isEngineText, isInlineBox, isLineBreak, mayBeAutoHyphenated, rangeOf, READS_ITS_CHILDREN, rowsAmong, SIDE_BY_SIDE, wordRuns } from './word-space.js';
|
|
18
|
+
import { blockChildrenOf, footerBeforeRows, headerAfterRows, isAtom, isEngineText, isInlineBox, isLineBreak, mayBeAutoHyphenated, rangeOf, READS_ITS_CHILDREN, rowsAmong, SIDE_BY_SIDE, wordRuns } from './word-space.js';
|
|
19
19
|
/** The Compositor's own `<br>`, found by the browser and never by splitting the attribute here (the walkers below run per box). */
|
|
20
20
|
const BREAK_SELECTOR = `br${selectorOf(BREAK)}`;
|
|
21
21
|
/**
|
|
@@ -28,7 +28,7 @@ const sharesLine = (aTop, aBottom, bTop, bBottom) => Math.min(aBottom, bBottom)
|
|
|
28
28
|
/** A character a word is made of: anything `BREAKING_SPACE` does not divide at. */
|
|
29
29
|
const WORD_CHAR = /[\S ]/;
|
|
30
30
|
/** A `display` whose inline content CSS 2.1 §9.2.1.1 wraps in anonymous block boxes — a block container's. A flex or grid container makes a run an anonymous item and a table an anonymous cell, which are other boxes and other questions. */
|
|
31
|
-
const holdsAnonymousBlocks = (display) => !/flex|grid|-webkit-box/.test(display) && (!/table/.test(display) || /^table-(cell|caption)$/.test(display));
|
|
31
|
+
export const holdsAnonymousBlocks = (display) => !/flex|grid|-webkit-box/.test(display) && (!/table/.test(display) || /^table-(cell|caption)$/.test(display));
|
|
32
32
|
const GAP_MIN = 0.75; // px — a third rect-reading rule, learned from the differential: half-leading float arithmetic leaves sub-pixel residue between a text box's last line and its border, and reporting that residue as a gap fabricates Class C cuts that bypass keeps. Real gaps (padding, margins, constrained heights) are ≥ 1px; noise stays under half a pixel.
|
|
33
33
|
/**
|
|
34
34
|
* Read one settled layout into an immutable snapshot — obtaining it seals the mutation phase (*render-identical conditions*, I5, by type).
|
|
@@ -91,6 +91,18 @@ export function takeReport(container, { contentHeight }) {
|
|
|
91
91
|
list.splice(last, 0, footer); // `last` moved down by one with the removal, so this is the place after it
|
|
92
92
|
footer.laidOutLast = moved = true;
|
|
93
93
|
}
|
|
94
|
+
// The header stands first, the mirror (*thead-after-rows-and-tall-footer-lose-rows*, 2026-11-07): §17.2 lays a `table-header-group` out *"before all other rows and row groups"*, so one written after them is moved before the first. Its words stay after the rows in the word space, which is why the Stonehand offers no place inside it or right after it, and why the driver refuses one that does not repeat: only a copy can show it on a page before its words.
|
|
95
|
+
for (const list of [box.blockChildren, box.children]) {
|
|
96
|
+
const h = list.findIndex((c) => headerAfterRows(c.el));
|
|
97
|
+
if (h < 0)
|
|
98
|
+
continue;
|
|
99
|
+
const first = list.findIndex((c) => /^table-row(-group)?$/.test(win.getComputedStyle(c.el).display));
|
|
100
|
+
if (first < 0 || first > h)
|
|
101
|
+
continue;
|
|
102
|
+
const [header] = list.splice(h, 1);
|
|
103
|
+
list.splice(first, 0, header);
|
|
104
|
+
header.laidOutFirst = moved = true;
|
|
105
|
+
}
|
|
94
106
|
}
|
|
95
107
|
/**
|
|
96
108
|
* The anonymous boxes (*the anonymous box is in the procession*, 2026-09-29; CSS 2.1 §9.2.1.1). A block container holding a block-level box beside inline content wraps each maximal run of that content in an anonymous block box, and css-break-3 §4.1 divides the result like any procession: a Class A point between the run and the block beside it, Class B points between its lines, and no Class C point where it stands, since a line is child content. The procession used to be the element tree's block children alone, so a run had no box: its lines were read as nothing but the distance they opened, a start gap before the first block child and an end gap after the last, and a page edge crossing thirteen trailing lines shelled them blank (`packages/essay/cases/76-the-line-before-the-first-block`).
|
|
@@ -7,6 +7,8 @@ export default {
|
|
|
7
7
|
id: ['en-us', 'en'],
|
|
8
8
|
leftmin: 2,
|
|
9
9
|
rightmin: 3,
|
|
10
|
+
// The word is its ASCII letters: hyphen.tex's patterns know no other, so an accented word yields nothing, as before. What stands around it, punctuation, quotation marks, brackets and a possessive's `'s`, moves no offset (Codeberg issue 6): until 2026-11-07 `computer,` had no candidates and `computer` had them. An apostrophe inside a word is not a letter here, where Italian reads an elision, since the patterns were built for TeX, which reads `don't` as two words.
|
|
11
|
+
word: /^(\P{L}*)([a-zA-Z]+)((?:['’]s)?\P{L}*)$/u,
|
|
10
12
|
// hyphen.tex's own exception list: words the patterns get wrong, hyphenations given literally.
|
|
11
13
|
exceptions: ['as-so-ciate', 'as-so-ciates', 'dec-li-na-tion', 'oblig-a-tory', 'phil-an-thropic', 'present', 'presents', 'project', 'projects', 'reci-procity', 're-cog-ni-zance', 'ref-or-ma-tion', 'ret-ri-bu-tion', 'ta-ble'],
|
|
12
14
|
patterns: [
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vendored Italian hyphenation patterns, hyph-it.tex version 4.9 of 2014-04-22 from the hyph-utf8 package (github.com/hyphenation/tex-hyphen), which follow the Recommendation UNI 6461. TeX's word boundary `.` is written `_` here, as `src/hyphenate.js` expects. Data, not code: the trie is built by src/hyphenate.js.
|
|
3
|
+
*
|
|
4
|
+
* Copyright (C) 2008-2011 Claudio Beccari, available under LPPL 1.3 or later or under the MIT licence, taken here under MIT:
|
|
5
|
+
*
|
|
6
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
7
|
+
*
|
|
8
|
+
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
9
|
+
*
|
|
10
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
11
|
+
*
|
|
12
|
+
* @packageDocumentation
|
|
13
|
+
*/
|
|
14
|
+
declare const _default: {
|
|
15
|
+
id: string[];
|
|
16
|
+
leftmin: number;
|
|
17
|
+
rightmin: number;
|
|
18
|
+
word: RegExp;
|
|
19
|
+
patterns: string[];
|
|
20
|
+
};
|
|
21
|
+
export default _default;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vendored Italian hyphenation patterns, hyph-it.tex version 4.9 of 2014-04-22 from the hyph-utf8 package (github.com/hyphenation/tex-hyphen), which follow the Recommendation UNI 6461. TeX's word boundary `.` is written `_` here, as `src/hyphenate.js` expects. Data, not code: the trie is built by src/hyphenate.js.
|
|
3
|
+
*
|
|
4
|
+
* Copyright (C) 2008-2011 Claudio Beccari, available under LPPL 1.3 or later or under the MIT licence, taken here under MIT:
|
|
5
|
+
*
|
|
6
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
7
|
+
*
|
|
8
|
+
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
9
|
+
*
|
|
10
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
11
|
+
*
|
|
12
|
+
* @packageDocumentation
|
|
13
|
+
*/
|
|
14
|
+
export default ({
|
|
15
|
+
id: ['it-it', 'it'],
|
|
16
|
+
leftmin: 2,
|
|
17
|
+
rightmin: 2,
|
|
18
|
+
// Accents and elisions are ordinary in Italian, and a word in running text may carry its punctuation: the core is what the patterns read, apostrophes included, because they have patterns of their own.
|
|
19
|
+
word: /^(\P{L}*)([\p{L}'’]+?)(\P{L}*)$/u,
|
|
20
|
+
patterns: [
|
|
21
|
+
"_a3p2n", "_anti1", "_anti3m2n", "_bio1", "_ca4p3s", "_circu2m1", "_contro1", "_di2s3cine", "_e2x1eu", "_fran2k3", "_free3", "_li3p2sa",
|
|
22
|
+
"_narco1", "_opto1", "_orto3p2", "_para1", "_ph2l", "_ph2r", "_poli3p2", "_pre1", "_p2s", "_re1i2scr", "_sha2re3", "_tran2s3c",
|
|
23
|
+
"_tran2s3d", "_tran2s3l", "_tran2s3n", "_tran2s3p", "_tran2s3r", "_tran2s3t", "_su2b3lu", "_su2b3r", "_wa2g3n", "_wel2t1", "2'2", "a1ia",
|
|
24
|
+
"a1ie", "a1io", "a1iu", "a1uo", "a1ya", "2at_", "e1iu", "e2w", "o1ia", "o1ie", "o1io", "o1iu",
|
|
25
|
+
"1b", "2bb", "2bc", "2bd", "2bf", "2bm", "2bn", "2bp", "2bs", "2bt", "2bv", "b2l",
|
|
26
|
+
"b2r", "2b_", "2b'", "1c", "2cb", "2cc", "2cd", "2cf", "2ck", "2cm", "2cn", "2cq",
|
|
27
|
+
"2cs", "2ct", "2cz", "2chh", "c2h", "2ch_", "2ch'_", "2ch''_", "2chb", "ch2r", "2chn", "c2l",
|
|
28
|
+
"c2r", "2c_", "2c'", "_c2", "1d", "2db", "2dd", "2dg", "2dl", "2dm", "2dn", "2dp",
|
|
29
|
+
"d2r", "2ds", "2dt", "2dv", "2dw", "2d_", "2d'", "_d2", "1f", "2fb", "2fg", "2ff",
|
|
30
|
+
"2fn", "f2l", "f2r", "2fs", "2ft", "2f_", "2f'", "1g", "2gb", "2gd", "2gf", "2gg",
|
|
31
|
+
"g2h", "g2l", "2gm", "g2n", "2gp", "g2r", "2gs", "2gt", "2gv", "2gw", "2gz", "2gh2t",
|
|
32
|
+
"2g_", "2g'", "_h2", "1h", "2hb", "2hd", "2hh", "hi3p2n", "h2l", "2hm", "2hn", "2hr",
|
|
33
|
+
"2hv", "2h_", "2h'", "_j2", "1j", "2j_", "2j'", "_k2", "1k", "2kg", "2kf", "k2h",
|
|
34
|
+
"2kk", "k2l", "2km", "k2r", "2ks", "2kt", "2k_", "2k'", "1l", "2lb", "2lc", "2ld",
|
|
35
|
+
"2l3f2", "2lg", "l2h", "l2j", "2lk", "2ll", "2lm", "2ln", "2lp", "2lq", "2lr", "2ls",
|
|
36
|
+
"2lt", "2lv", "2lw", "2lz", "2l_", "2l'_", "2l''", "1m", "2mb", "2mc", "2mf", "2ml",
|
|
37
|
+
"2mm", "2mn", "2mp", "2mq", "2mr", "2ms", "2mt", "2mv", "2mw", "2m_", "2m'", "1n",
|
|
38
|
+
"2nb", "2nc", "2nd", "2nf", "2ng", "2nk", "2nl", "2nm", "2nn", "2np", "2nq", "2nr",
|
|
39
|
+
"2ns", "n2s3fer", "2nt", "2nv", "2nz", "n2g3n", "2nheit", "2n_", "2n'", "1p", "2pd", "p2h",
|
|
40
|
+
"p2l", "2pn", "3p2ne", "2pp", "p2r", "2ps", "3p2sic", "2pt", "2pz", "2p_", "2p'", "1q",
|
|
41
|
+
"2qq", "2q_", "2q'", "1r", "2rb", "2rc", "2rd", "2rf", "r2h", "2rg", "2rk", "2rl",
|
|
42
|
+
"2rm", "2rn", "2rp", "2rq", "2rr", "2rs", "2rt", "r2t2s3", "2rv", "2rx", "2rw", "2rz",
|
|
43
|
+
"2r_", "2r'", "1s2", "2shm", "2sh_", "2sh'", "2s3s", "s4s3m", "2s3p2n", "2stb", "2stc", "2std",
|
|
44
|
+
"2stf", "2stg", "2stm", "2stn", "2stp", "2sts", "2stt", "2stv", "2sz", "4s_", "4s'_", "4s''",
|
|
45
|
+
"_t2", "1t", "2tb", "2tc", "2td", "2tf", "2tg", "t2h", "2th_", "t2l", "2tm", "2tn",
|
|
46
|
+
"2tp", "t2r", "t2s", "3t2sch", "2tt", "t2t3s", "2tv", "2tw", "t2z", "2tzk", "tz2s", "2t_",
|
|
47
|
+
"2t'_", "2t''", "1v", "2vc", "v2l", "v2r", "2vv", "2v_", "2v'_", "2v''", "1w", "w2h",
|
|
48
|
+
"wa2r", "2w1y", "2w_", "2w'", "1x", "2xb", "2xc", "2xf", "2xh", "2xm", "2xp", "2xt",
|
|
49
|
+
"2xw", "2x_", "2x'", "y1ou", "y1i", "1z", "2zb", "2zd", "2zl", "2zn", "2zp", "2zt",
|
|
50
|
+
"2zs", "2zv", "2zz", "2z_", "2z'_", "2z''", "_z2",
|
|
51
|
+
]
|
|
52
|
+
});
|
package/dist/src/hyphenate.d.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*
|
|
8
8
|
* @packageDocumentation
|
|
9
9
|
*/
|
|
10
|
-
/** A pattern set as a language module supplies it
|
|
10
|
+
/** A pattern set as a language module supplies it, as `hyphen-patterns/en-us.js` and `hyphen-patterns/it.js` do. */
|
|
11
11
|
export type LanguageData = {
|
|
12
12
|
/** Every `lang` value the set answers, lower-case. */
|
|
13
13
|
id: string[];
|
|
@@ -17,6 +17,8 @@ export type LanguageData = {
|
|
|
17
17
|
patterns: string[];
|
|
18
18
|
/** Hyphenations given literally, `-` at every division. */
|
|
19
19
|
exceptions?: string[];
|
|
20
|
+
/** What counts as a word, as three groups: what stands before it, the word the patterns read, and what stands after it. Absent, plain ASCII letters and nothing around them. */
|
|
21
|
+
word?: RegExp;
|
|
20
22
|
};
|
|
21
23
|
/** A registered language: the trie built once. A trie node maps a letter to its child node and `'$'` to the digit list of the pattern ending there, which is why its values are untyped. */
|
|
22
24
|
export type Language = {
|
|
@@ -25,6 +27,7 @@ export type Language = {
|
|
|
25
27
|
exceptions: Map<string, string>;
|
|
26
28
|
leftmin: number;
|
|
27
29
|
rightmin: number;
|
|
30
|
+
word: RegExp;
|
|
28
31
|
};
|
|
29
32
|
/** css-text-4 §6.3.4's three values; a null or an absence is `auto`. */
|
|
30
33
|
export type HyphenateLimits = {
|
|
@@ -53,4 +56,4 @@ export declare function resolveLimits(lang: Pick<Language, 'leftmin' | 'rightmin
|
|
|
53
56
|
*
|
|
54
57
|
* @param lang - from `languageFor`; null yields no candidates.
|
|
55
58
|
*/
|
|
56
|
-
export declare function hyphenationOffsets(
|
|
59
|
+
export declare function hyphenationOffsets(text: string, lang: Language | null, limits?: HyphenateLimits): number[];
|
package/dist/src/hyphenate.js
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
* @packageDocumentation
|
|
9
9
|
*/
|
|
10
10
|
import enUs from './hyphen-patterns/en-us.js';
|
|
11
|
+
import it from './hyphen-patterns/it.js';
|
|
11
12
|
const LANGS = new Map();
|
|
12
13
|
/** Build a language's trie once. Exposed as data-in, function-out so a future language module registers the same way. */
|
|
13
14
|
export function registerLanguage(data) {
|
|
@@ -36,12 +37,13 @@ export function registerLanguage(data) {
|
|
|
36
37
|
for (const ex of data.exceptions ?? []) {
|
|
37
38
|
exceptions.set(ex.replace(/-/g, ''), ex);
|
|
38
39
|
}
|
|
39
|
-
const lang = { trie, exceptions, leftmin: data.leftmin, rightmin: data.rightmin };
|
|
40
|
+
const lang = { trie, exceptions, leftmin: data.leftmin, rightmin: data.rightmin, word: data.word ?? /^()([a-zA-Z]+)()$/ };
|
|
40
41
|
for (const id of data.id)
|
|
41
42
|
LANGS.set(id, lang);
|
|
42
43
|
return lang;
|
|
43
44
|
}
|
|
44
45
|
registerLanguage(enUs);
|
|
46
|
+
registerLanguage(it);
|
|
45
47
|
/** Resolve a lang attribute value to a registered language, or null (no language, no candidates — auto-hyphenation is never guessed). */
|
|
46
48
|
export function languageFor(langAttr) {
|
|
47
49
|
if (!langAttr)
|
|
@@ -66,13 +68,19 @@ export function resolveLimits(lang, limits = {}) {
|
|
|
66
68
|
*
|
|
67
69
|
* @param lang - from `languageFor`; null yields no candidates.
|
|
68
70
|
*/
|
|
69
|
-
export function hyphenationOffsets(
|
|
71
|
+
export function hyphenationOffsets(text, lang, limits = {}) {
|
|
70
72
|
if (!lang)
|
|
71
73
|
return [];
|
|
72
74
|
const { before, after, total } = resolveLimits(lang, limits);
|
|
73
|
-
|
|
75
|
+
const found = lang.word.exec(text);
|
|
76
|
+
if (!found)
|
|
74
77
|
return [];
|
|
75
|
-
const
|
|
78
|
+
const lead = found[1].length;
|
|
79
|
+
const word = found[2];
|
|
80
|
+
if (word.length < total || word.length < before + after)
|
|
81
|
+
return [];
|
|
82
|
+
// Both apostrophes are one letter to a pattern; the replacement keeps every offset.
|
|
83
|
+
const lower = word.toLowerCase().replace(/’/g, "'");
|
|
76
84
|
const exception = lang.exceptions.get(lower);
|
|
77
85
|
if (exception !== undefined) {
|
|
78
86
|
const offsets = [];
|
|
@@ -80,7 +88,7 @@ export function hyphenationOffsets(word, lang, limits = {}) {
|
|
|
80
88
|
for (const part of exception.split('-').slice(0, -1)) {
|
|
81
89
|
pos += part.length;
|
|
82
90
|
if (pos >= before && word.length - pos >= after)
|
|
83
|
-
offsets.push(pos);
|
|
91
|
+
offsets.push(lead + pos);
|
|
84
92
|
}
|
|
85
93
|
return offsets;
|
|
86
94
|
}
|
|
@@ -106,7 +114,7 @@ export function hyphenationOffsets(word, lang, limits = {}) {
|
|
|
106
114
|
for (let p = 2; p < marked.length - 1; p++) {
|
|
107
115
|
const off = p - 1;
|
|
108
116
|
if (points[p] % 2 === 1 && off >= before && word.length - off >= after)
|
|
109
|
-
offsets.push(off);
|
|
117
|
+
offsets.push(lead + off);
|
|
110
118
|
}
|
|
111
119
|
return offsets;
|
|
112
120
|
}
|
package/dist/src/measure.d.ts
CHANGED
|
@@ -12,7 +12,9 @@ export type MeasureContext = ReturnType<typeof createMeasureContext>;
|
|
|
12
12
|
/**
|
|
13
13
|
* The intake under *render-identical conditions* (I5): refuse to adjudicate under conditions print will not reproduce. `relaxDpr` is the preview's escape hatch only — decisions are then valid for the screen being looked at, not for print; no gate ever sets it.
|
|
14
14
|
*
|
|
15
|
-
*
|
|
15
|
+
* A vertical or sideways root is refused by name too (Codeberg issue 12): every read in this engine is horizontal, the lines by vertical overlap, the cut by a y, the page area by its height, so under `writing-mode: sideways-lr` on the root the text of a positioned paragraph fell below the clip and was never resumed, and the printer's tiling invariant refused what the engine should have. Vertical writing is outside the beta, and a refusal that says so at intake is cheaper than one three tools later.
|
|
16
|
+
*
|
|
17
|
+
* @throws Error — bare and deliberate (`src/` may not import BelType's error types): a device pixel ratio other than 1 without `relaxDpr`, a document root whose line-height is not explicit (*render-identical conditions*, I5), or a document root whose writing mode is not `horizontal-tb`.
|
|
16
18
|
*/
|
|
17
19
|
export declare function assertRenderConditions(doc: Document, { relaxDpr }?: {
|
|
18
20
|
relaxDpr?: boolean;
|
|
@@ -64,13 +66,13 @@ export type PagePublish = {
|
|
|
64
66
|
* @param contentWidthPx - the page's true content width — the one geometry decisions are valid under (*render-identical conditions*, I5).
|
|
65
67
|
*/
|
|
66
68
|
export declare function createMeasureContext(doc: Document, contentWidthPx: number): {
|
|
67
|
-
container:
|
|
69
|
+
container: HTMLDivElement;
|
|
68
70
|
/**
|
|
69
71
|
* Lay out a feed of nodes and force one layout. The caller obtains geometry only through a Gauge report taken afterward — obtaining the report seals the mutation phase (*render-identical conditions*, I5, by type; see gauge.js).
|
|
70
72
|
*
|
|
71
73
|
* @param nodes - cloned feed content; never source elements (*the source document is never written*, C5, and never moved).
|
|
72
74
|
* @param publish - what the page the feed is for publishes on its host (*the page carries its conditions*, 2026-10-21), written on the container so a flow site that reads a page fact is measured with it standing; absent, the container carries none, and such a site reads its reservation.
|
|
73
75
|
*/
|
|
74
|
-
measure(nodes: Node[], publish?: PagePublish | null):
|
|
76
|
+
measure(nodes: Node[], publish?: PagePublish | null): HTMLDivElement;
|
|
75
77
|
dispose(): void;
|
|
76
78
|
};
|
package/dist/src/measure.js
CHANGED
|
@@ -15,17 +15,23 @@ const NEUTRALIZE_ID = '__beltype-neutralize';
|
|
|
15
15
|
/**
|
|
16
16
|
* The intake under *render-identical conditions* (I5): refuse to adjudicate under conditions print will not reproduce. `relaxDpr` is the preview's escape hatch only — decisions are then valid for the screen being looked at, not for print; no gate ever sets it.
|
|
17
17
|
*
|
|
18
|
-
*
|
|
18
|
+
* A vertical or sideways root is refused by name too (Codeberg issue 12): every read in this engine is horizontal, the lines by vertical overlap, the cut by a y, the page area by its height, so under `writing-mode: sideways-lr` on the root the text of a positioned paragraph fell below the clip and was never resumed, and the printer's tiling invariant refused what the engine should have. Vertical writing is outside the beta, and a refusal that says so at intake is cheaper than one three tools later.
|
|
19
|
+
*
|
|
20
|
+
* @throws Error — bare and deliberate (`src/` may not import BelType's error types): a device pixel ratio other than 1 without `relaxDpr`, a document root whose line-height is not explicit (*render-identical conditions*, I5), or a document root whose writing mode is not `horizontal-tb`.
|
|
19
21
|
*/
|
|
20
22
|
export function assertRenderConditions(doc, { relaxDpr = false } = {}) {
|
|
21
23
|
const win = doc.defaultView;
|
|
22
24
|
if (!relaxDpr && win.devicePixelRatio !== 1) {
|
|
23
25
|
throw new Error(`I5: unit device pixel ratio required for adjudication, got ${win.devicePixelRatio}`);
|
|
24
26
|
}
|
|
25
|
-
const
|
|
27
|
+
const root = win.getComputedStyle(doc.documentElement);
|
|
28
|
+
const lh = root.lineHeight;
|
|
26
29
|
if (!/^-?[\d.]+px$/.test(lh)) {
|
|
27
30
|
throw new Error(`I5 (DPR ruling): explicit line-height required, document root computes '${lh}'`);
|
|
28
31
|
}
|
|
32
|
+
if (root.writingMode && root.writingMode !== 'horizontal-tb') {
|
|
33
|
+
throw new Error(`a vertical or sideways root is outside this engine's beta: the document root computes writing-mode '${root.writingMode}', and every read here is horizontal (the line by vertical overlap, the cut by a y). Write the document horizontal-tb, or print it with another engine.`);
|
|
34
|
+
}
|
|
29
35
|
}
|
|
30
36
|
/**
|
|
31
37
|
* Await font readiness once — late-arriving truth handled before the first measure, never during adjudication.
|
|
@@ -134,16 +140,14 @@ export function createMeasureContext(doc, contentWidthPx) {
|
|
|
134
140
|
style.textContent = `#${CONTAINER_ID}, #${CONTAINER_ID} * { break-before: auto !important; break-after: auto !important; break-inside: auto !important; orphans: 2 !important; widows: 2 !important; transform: none !important; rotate: none !important; scale: none !important; translate: none !important; perspective: none !important; }`;
|
|
135
141
|
doc.head.appendChild(style);
|
|
136
142
|
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
doc.body.appendChild(container);
|
|
142
|
-
}
|
|
143
|
+
// Each context has a container of its own, so two fills in flight never measure in each other's. They share the one id on purpose, transiently: the neutralizing sheet and `reads.ts` select by it, at the specificity the sheet needs against an author's `!important`.
|
|
144
|
+
const container = doc.createElement('div');
|
|
145
|
+
container.id = CONTAINER_ID;
|
|
146
|
+
doc.body.appendChild(container);
|
|
143
147
|
// flow-root: child margins stay inside, so the container's box is the measured flow's coordinate space. Off-viewport, never display:none — display:none has no geometry.
|
|
144
148
|
const css = `position: absolute; left: -100000px; top: 0; width: ${contentWidthPx}px; display: flow-root;`;
|
|
145
149
|
container.style.cssText = css;
|
|
146
|
-
/**
|
|
150
|
+
/** A context can stand idle while another runs (*the pages are cut as far as they are asked*, 2026-10-12), and a host may move what it wears, so every measure makes sure of the sheet, the container and the width before it lays anything out. Where nothing moved, all three are already so. */
|
|
147
151
|
const ensure = () => {
|
|
148
152
|
if (!style.isConnected)
|
|
149
153
|
doc.head.appendChild(style);
|
|
@@ -171,7 +175,8 @@ export function createMeasureContext(doc, contentWidthPx) {
|
|
|
171
175
|
},
|
|
172
176
|
dispose() {
|
|
173
177
|
container.remove();
|
|
174
|
-
|
|
178
|
+
if (!doc.querySelector(`#${CONTAINER_ID}`))
|
|
179
|
+
style.remove();
|
|
175
180
|
}
|
|
176
181
|
};
|
|
177
182
|
}
|
package/dist/src/reads.d.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*
|
|
8
8
|
* **A missing target shows nothing**: no declaration is delivered for it, the fallback `""` stands, the pseudo-element still has its box (the leader the author drew still draws), and the console names the link once per paginate.
|
|
9
9
|
*
|
|
10
|
-
* **The loop is a consumer's too, over a chain of its own** (*the engine knows no view*, `.claude/decisions/project/the-engine-knows-no-view.md`, ruling 3). `settleReads`'s `run` and `blocksOf` are the door: a view that holds its own pages settles through this loop, with a `run` that refills the dirty entries of its chain, and never through a copy of it. What the loop assumes of its host, read in its body and its helpers: the sites are found in `doc`'s sheets and matched among `originals` (the whole document where none are given), and a site or a target counts only where it stands inside `blocksOf()`'s blocks, since the position index places it; so `originals` are the boxes that hold the blocks, never a presented copy of them. A target is `doc.getElementById`'s answer
|
|
10
|
+
* **The loop is a consumer's too, over a chain of its own** (*the engine knows no view*, `.claude/decisions/project/the-engine-knows-no-view.md`, ruling 3). `settleReads`'s `run` and `blocksOf` are the door: a view that holds its own pages settles through this loop, with a `run` that refills the dirty entries of its chain, and never through a copy of it. What the loop assumes of its host, read in its body and its helpers: the sites are found in `doc`'s sheets and matched among `originals` (the whole document where none are given), and a site or a target counts only where it stands inside `blocksOf()`'s blocks, since the position index places it; so `originals` are the boxes that hold the blocks, never a presented copy of them. A target is the first element in tree order carrying the id among `originals` (`doc.getElementById`'s answer where none are given), which holds where the source boxes precede every copy that keeps the id, as `<beltype-root>` keeps its originals before its copies, or where the copies carry no id; a host's own element that carries an author's id is outside the originals and is never a target, and a `target-text()` target outside `blocksOf()`'s blocks shows nothing, as a counter or page target there does. The blocks are any elements in document order: nothing asks that they share a parent or be `body`'s children, since the position index, the counter walk and `pathOf` each walk one block on its own. The counter walk's ancestors are `html` and `body`, the two the driver's own walk reads, so another ancestor of the blocks must carry no counter operation. A changed site is measured on a clone of its block in the measure container, at its page's content width, the ruler the run measures with. The run's result carries an `account` whose entries have the driver's shape (`pos`, `cut`, `carried`, `blank`, `trace.forced`, and `closes` with `pageNumber`, `contentW`, `contentH` and `strings`), every address in `blocksOf()`'s numbering, and the `index` it was handed; and, where its pages publish values of their own, `laidFacts`, the page values each page was laid out under (a flow site reads them), which the loop compares the truth with in place of the table it handed the run (a run that returns none was laid out under the table it was handed, as the driver's is; see CHANGELOG 2026-10-28); a layout sent round again is handed `resume.at`, the addresses of the moved boxes, which such a `run` maps to the entries they dirty. The values reach every element in `doc`'s own tree through one adopted sheet, and the page facts are the page hosts' (`chase.js`). One assumption was the root's alone and is a parameter: the sheet that hides a reservation scopes its rules to `beltype-root`, and `hide` names another scope.
|
|
11
11
|
*
|
|
12
12
|
* @packageDocumentation
|
|
13
13
|
*/
|
|
@@ -224,7 +224,7 @@ export declare function linesOfSites<S extends {
|
|
|
224
224
|
*
|
|
225
225
|
* **A layout sent round again resumes from the one before it** (*delivery resumes from the moved page*, 2026-10-21). A delivered value that moves a line is an edit at its site's page, so `run` is handed `resume`, the layout just checked and the addresses of the boxes whose lines moved, and the driver restarts one page before the first of them, re-cuts, and stops where it converges past the last, exactly as it resumes from a host's edit. The result's `resumed` and `why` stay the call's: two resumes compose into one from the prior the host handed (`resume.js`' `composeResumed`), a whole layout anywhere in the loop makes `resumed` null, and each resumed layout leaves a `cicero:reads-run` measure naming the pages it cut again.
|
|
226
226
|
*
|
|
227
|
-
* @param how - `run` lays the document out once, whole or resumed (`because`: the references whose page number moved a line of their own in the run before, when this is not the first; `facts`: the page values a flow site reads, per page, as the run before decided them, or null for the reservation; it returns `laidFacts` beside `account` when the page values it was laid out under are not the ones it was handed); `blocksOf` names the top-level blocks; `originals` the intake's top-level boxes, where the document has been presented (see {@link findSites}); `warm` and `warmFacts` the tables the previous run's layout was cut under, for a run that resumes; `hide` that pages are shown before the run is complete (*the pages are cut as far as they are asked*), so the reservations still standing are painted invisible until the true numbers are delivered, under `<beltype-root>` for `true` and under the selector a string names for a host that is not the root; `keep` the memo's door, through which the site search, the position index and the counter walk take the parts of the boxes no edit replaced (*a resumed run keeps its reads*, 2026-10-22).
|
|
227
|
+
* @param how - `run` lays the document out once, whole or resumed (`because`: the references whose page number moved a line of their own in the run before, when this is not the first; `facts`: the page values a flow site reads, per page, as the run before decided them, or null for the reservation; it returns `laidFacts` beside `account` when the page values it was laid out under are not the ones it was handed); `blocksOf` names the top-level blocks; `originals` the intake's top-level boxes, where the document has been presented (see {@link findSites}); `warm` and `warmFacts` the tables the previous run's layout was cut under, for a run that resumes; `hide` that pages are shown before the run is complete (*the pages are cut as far as they are asked*), so the reservations still standing are painted invisible until the true numbers are delivered, under `<beltype-root>` for `true` and under the selector a string names for a host that is not the root; `keep` the memo's door, through which the site search, the position index and the counter walk take the parts of the boxes no edit replaced (*a resumed run keeps its reads*, 2026-10-22). A `run` that answers `complete: false` laid out only part of the document (a view's chain that stopped short): the loop ends there, without checking or delivering page values, so the reservations stay hidden and the values it returns are the ones that layout was cut under; the driver's own run is always complete.
|
|
228
228
|
*/
|
|
229
229
|
export declare function settleReads<R extends {
|
|
230
230
|
account: any[];
|
|
@@ -232,6 +232,7 @@ export declare function settleReads<R extends {
|
|
|
232
232
|
resumed?: Resumed | null;
|
|
233
233
|
why?: string | null;
|
|
234
234
|
laidFacts?: PagePublish[] | null;
|
|
235
|
+
complete?: boolean;
|
|
235
236
|
}>(doc: Document, { run, blocksOf, originals, warm, warmFacts, hide, keep }: {
|
|
236
237
|
run: (laid: Laid) => Promise<R>;
|
|
237
238
|
blocksOf: () => Element[];
|