wolfy-reader 0.1.0

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.
Files changed (233) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +277 -0
  3. package/dist/core/book.d.ts +75 -0
  4. package/dist/core/book.d.ts.map +1 -0
  5. package/dist/core/book.js +2 -0
  6. package/dist/core/book.js.map +1 -0
  7. package/dist/core/errors.d.ts +17 -0
  8. package/dist/core/errors.d.ts.map +1 -0
  9. package/dist/core/errors.js +29 -0
  10. package/dist/core/errors.js.map +1 -0
  11. package/dist/core/format.d.ts +13 -0
  12. package/dist/core/format.d.ts.map +1 -0
  13. package/dist/core/format.js +2 -0
  14. package/dist/core/format.js.map +1 -0
  15. package/dist/core/graphemes.d.ts +36 -0
  16. package/dist/core/graphemes.d.ts.map +1 -0
  17. package/dist/core/graphemes.js +62 -0
  18. package/dist/core/graphemes.js.map +1 -0
  19. package/dist/core/index.d.ts +11 -0
  20. package/dist/core/index.d.ts.map +1 -0
  21. package/dist/core/index.js +6 -0
  22. package/dist/core/index.js.map +1 -0
  23. package/dist/core/lookup.d.ts +10 -0
  24. package/dist/core/lookup.d.ts.map +1 -0
  25. package/dist/core/lookup.js +16 -0
  26. package/dist/core/lookup.js.map +1 -0
  27. package/dist/core/open.d.ts +12 -0
  28. package/dist/core/open.d.ts.map +1 -0
  29. package/dist/core/open.js +23 -0
  30. package/dist/core/open.js.map +1 -0
  31. package/dist/core/position.d.ts +121 -0
  32. package/dist/core/position.d.ts.map +1 -0
  33. package/dist/core/position.js +327 -0
  34. package/dist/core/position.js.map +1 -0
  35. package/dist/core/reading-text.d.ts +77 -0
  36. package/dist/core/reading-text.d.ts.map +1 -0
  37. package/dist/core/reading-text.js +144 -0
  38. package/dist/core/reading-text.js.map +1 -0
  39. package/dist/core/source.d.ts +17 -0
  40. package/dist/core/source.d.ts.map +1 -0
  41. package/dist/core/source.js +39 -0
  42. package/dist/core/source.js.map +1 -0
  43. package/dist/core/storage.d.ts +7 -0
  44. package/dist/core/storage.d.ts.map +1 -0
  45. package/dist/core/storage.js +2 -0
  46. package/dist/core/storage.js.map +1 -0
  47. package/dist/core/text.d.ts +18 -0
  48. package/dist/core/text.d.ts.map +1 -0
  49. package/dist/core/text.js +32 -0
  50. package/dist/core/text.js.map +1 -0
  51. package/dist/formats/epub/href.d.ts +14 -0
  52. package/dist/formats/epub/href.d.ts.map +1 -0
  53. package/dist/formats/epub/href.js +52 -0
  54. package/dist/formats/epub/href.js.map +1 -0
  55. package/dist/formats/epub/index.d.ts +3 -0
  56. package/dist/formats/epub/index.d.ts.map +1 -0
  57. package/dist/formats/epub/index.js +223 -0
  58. package/dist/formats/epub/index.js.map +1 -0
  59. package/dist/formats/epub/opf.d.ts +27 -0
  60. package/dist/formats/epub/opf.d.ts.map +1 -0
  61. package/dist/formats/epub/opf.js +110 -0
  62. package/dist/formats/epub/opf.js.map +1 -0
  63. package/dist/formats/epub/toc.d.ts +6 -0
  64. package/dist/formats/epub/toc.d.ts.map +1 -0
  65. package/dist/formats/epub/toc.js +88 -0
  66. package/dist/formats/epub/toc.js.map +1 -0
  67. package/dist/formats/fb2/index.d.ts +13 -0
  68. package/dist/formats/fb2/index.d.ts.map +1 -0
  69. package/dist/formats/fb2/index.js +317 -0
  70. package/dist/formats/fb2/index.js.map +1 -0
  71. package/dist/formats/index.d.ts +4 -0
  72. package/dist/formats/index.d.ts.map +1 -0
  73. package/dist/formats/index.js +4 -0
  74. package/dist/formats/index.js.map +1 -0
  75. package/dist/formats/text/index.d.ts +11 -0
  76. package/dist/formats/text/index.d.ts.map +1 -0
  77. package/dist/formats/text/index.js +201 -0
  78. package/dist/formats/text/index.js.map +1 -0
  79. package/dist/formats/xml.d.ts +33 -0
  80. package/dist/formats/xml.d.ts.map +1 -0
  81. package/dist/formats/xml.js +321 -0
  82. package/dist/formats/xml.js.map +1 -0
  83. package/dist/index.d.ts +27 -0
  84. package/dist/index.d.ts.map +1 -0
  85. package/dist/index.js +28 -0
  86. package/dist/index.js.map +1 -0
  87. package/dist/layout/chunk.d.ts +51 -0
  88. package/dist/layout/chunk.d.ts.map +1 -0
  89. package/dist/layout/chunk.js +131 -0
  90. package/dist/layout/chunk.js.map +1 -0
  91. package/dist/layout/index.d.ts +238 -0
  92. package/dist/layout/index.d.ts.map +1 -0
  93. package/dist/layout/index.js +476 -0
  94. package/dist/layout/index.js.map +1 -0
  95. package/dist/reader/index.d.ts +231 -0
  96. package/dist/reader/index.d.ts.map +1 -0
  97. package/dist/reader/index.js +958 -0
  98. package/dist/reader/index.js.map +1 -0
  99. package/dist/reader/input.d.ts +69 -0
  100. package/dist/reader/input.d.ts.map +1 -0
  101. package/dist/reader/input.js +75 -0
  102. package/dist/reader/input.js.map +1 -0
  103. package/dist/search/extract.d.ts +51 -0
  104. package/dist/search/extract.d.ts.map +1 -0
  105. package/dist/search/extract.js +401 -0
  106. package/dist/search/extract.js.map +1 -0
  107. package/dist/search/index.d.ts +11 -0
  108. package/dist/search/index.d.ts.map +1 -0
  109. package/dist/search/index.js +11 -0
  110. package/dist/search/index.js.map +1 -0
  111. package/dist/search/matcher.d.ts +56 -0
  112. package/dist/search/matcher.d.ts.map +1 -0
  113. package/dist/search/matcher.js +128 -0
  114. package/dist/search/matcher.js.map +1 -0
  115. package/dist/search/normalize.d.ts +48 -0
  116. package/dist/search/normalize.d.ts.map +1 -0
  117. package/dist/search/normalize.js +103 -0
  118. package/dist/search/normalize.js.map +1 -0
  119. package/dist/view/allowlist.d.ts +59 -0
  120. package/dist/view/allowlist.d.ts.map +1 -0
  121. package/dist/view/allowlist.js +198 -0
  122. package/dist/view/allowlist.js.map +1 -0
  123. package/dist/view/appearance.d.ts +137 -0
  124. package/dist/view/appearance.d.ts.map +1 -0
  125. package/dist/view/appearance.js +274 -0
  126. package/dist/view/appearance.js.map +1 -0
  127. package/dist/view/css.d.ts +24 -0
  128. package/dist/view/css.d.ts.map +1 -0
  129. package/dist/view/css.js +153 -0
  130. package/dist/view/css.js.map +1 -0
  131. package/dist/view/frame.d.ts +54 -0
  132. package/dist/view/frame.d.ts.map +1 -0
  133. package/dist/view/frame.js +980 -0
  134. package/dist/view/frame.js.map +1 -0
  135. package/dist/view/host.d.ts +160 -0
  136. package/dist/view/host.d.ts.map +1 -0
  137. package/dist/view/host.js +385 -0
  138. package/dist/view/host.js.map +1 -0
  139. package/dist/view/index.d.ts +12 -0
  140. package/dist/view/index.d.ts.map +1 -0
  141. package/dist/view/index.js +7 -0
  142. package/dist/view/index.js.map +1 -0
  143. package/dist/view/protocol.d.ts +220 -0
  144. package/dist/view/protocol.d.ts.map +1 -0
  145. package/dist/view/protocol.js +246 -0
  146. package/dist/view/protocol.js.map +1 -0
  147. package/dist/view/reference.d.ts +18 -0
  148. package/dist/view/reference.d.ts.map +1 -0
  149. package/dist/view/reference.js +25 -0
  150. package/dist/view/reference.js.map +1 -0
  151. package/dist/view/resources.d.ts +51 -0
  152. package/dist/view/resources.d.ts.map +1 -0
  153. package/dist/view/resources.js +242 -0
  154. package/dist/view/resources.js.map +1 -0
  155. package/dist/view/sanitize.d.ts +32 -0
  156. package/dist/view/sanitize.d.ts.map +1 -0
  157. package/dist/view/sanitize.js +226 -0
  158. package/dist/view/sanitize.js.map +1 -0
  159. package/dist/zip/central.d.ts +12 -0
  160. package/dist/zip/central.d.ts.map +1 -0
  161. package/dist/zip/central.js +72 -0
  162. package/dist/zip/central.js.map +1 -0
  163. package/dist/zip/crc32.d.ts +3 -0
  164. package/dist/zip/crc32.d.ts.map +1 -0
  165. package/dist/zip/crc32.js +28 -0
  166. package/dist/zip/crc32.js.map +1 -0
  167. package/dist/zip/eocd.d.ts +9 -0
  168. package/dist/zip/eocd.d.ts.map +1 -0
  169. package/dist/zip/eocd.js +84 -0
  170. package/dist/zip/eocd.js.map +1 -0
  171. package/dist/zip/errors.d.ts +19 -0
  172. package/dist/zip/errors.d.ts.map +1 -0
  173. package/dist/zip/errors.js +37 -0
  174. package/dist/zip/errors.js.map +1 -0
  175. package/dist/zip/index.d.ts +18 -0
  176. package/dist/zip/index.d.ts.map +1 -0
  177. package/dist/zip/index.js +78 -0
  178. package/dist/zip/index.js.map +1 -0
  179. package/dist/zip/inflate.d.ts +2 -0
  180. package/dist/zip/inflate.d.ts.map +1 -0
  181. package/dist/zip/inflate.js +43 -0
  182. package/dist/zip/inflate.js.map +1 -0
  183. package/dist/zip/source.d.ts +15 -0
  184. package/dist/zip/source.d.ts.map +1 -0
  185. package/dist/zip/source.js +34 -0
  186. package/dist/zip/source.js.map +1 -0
  187. package/package.json +75 -0
  188. package/src/core/book.ts +80 -0
  189. package/src/core/errors.ts +31 -0
  190. package/src/core/format.ts +14 -0
  191. package/src/core/graphemes.ts +73 -0
  192. package/src/core/index.ts +27 -0
  193. package/src/core/lookup.ts +16 -0
  194. package/src/core/open.ts +31 -0
  195. package/src/core/position.ts +485 -0
  196. package/src/core/reading-text.ts +200 -0
  197. package/src/core/source.ts +61 -0
  198. package/src/core/storage.ts +6 -0
  199. package/src/core/text.ts +35 -0
  200. package/src/formats/epub/href.ts +54 -0
  201. package/src/formats/epub/index.ts +235 -0
  202. package/src/formats/epub/opf.ts +143 -0
  203. package/src/formats/epub/toc.ts +120 -0
  204. package/src/formats/fb2/index.ts +348 -0
  205. package/src/formats/index.ts +3 -0
  206. package/src/formats/text/index.ts +208 -0
  207. package/src/formats/xml.ts +326 -0
  208. package/src/index.ts +26 -0
  209. package/src/layout/chunk.ts +169 -0
  210. package/src/layout/index.ts +573 -0
  211. package/src/reader/index.ts +1206 -0
  212. package/src/reader/input.ts +122 -0
  213. package/src/search/extract.ts +403 -0
  214. package/src/search/index.ts +10 -0
  215. package/src/search/matcher.ts +187 -0
  216. package/src/search/normalize.ts +122 -0
  217. package/src/view/allowlist.ts +273 -0
  218. package/src/view/appearance.ts +380 -0
  219. package/src/view/css.ts +172 -0
  220. package/src/view/frame.ts +1018 -0
  221. package/src/view/host.ts +527 -0
  222. package/src/view/index.ts +24 -0
  223. package/src/view/protocol.ts +412 -0
  224. package/src/view/reference.ts +30 -0
  225. package/src/view/resources.ts +265 -0
  226. package/src/view/sanitize.ts +266 -0
  227. package/src/zip/central.ts +85 -0
  228. package/src/zip/crc32.ts +30 -0
  229. package/src/zip/eocd.ts +97 -0
  230. package/src/zip/errors.ts +41 -0
  231. package/src/zip/index.ts +114 -0
  232. package/src/zip/inflate.ts +41 -0
  233. package/src/zip/source.ts +51 -0
package/dist/index.js ADDED
@@ -0,0 +1,28 @@
1
+ /*! wolfy-reader v0.1.0 | @license MIT | (c) Vitaliy Tkachuk | github.com/vitaliy-tkachuk/wolfy-reader */
2
+ /**
3
+ * The package root: the browser-facing reader facade plus the headless core it
4
+ * operates on.
5
+ *
6
+ * import { open, render } from 'wolfy-reader';
7
+ * import { epub } from 'wolfy-reader/epub';
8
+ *
9
+ * Core travels with the facade because `render` takes a `Book` and `open` is the
10
+ * only public way to make one — splitting them would make the common case a
11
+ * three-import dance, and the facade's own surface already names `Position`,
12
+ * `TocItem` and `SentenceRange` in its signatures.
13
+ *
14
+ * Both re-exports resolve to the same emitted modules as `wolfy-reader/core`, so
15
+ * there is one `open`, one `Position` model and one set of error constructors
16
+ * however a consumer reaches them — `instanceof BookError` holds across entries.
17
+ *
18
+ * Headless consumers should import `wolfy-reader/core` instead. This root reaches
19
+ * `src/layout` and `src/view`; it is import-safe under Node today and the pack
20
+ * fidelity check keeps it that way, but only `/core` carries the guarantee.
21
+ *
22
+ * Format decoders are deliberately absent: each is its own subpath because their
23
+ * closures differ by an order of magnitude — only `epub` pulls the ZIP reader —
24
+ * and `open(input, { formats })` takes an explicit list by design.
25
+ */
26
+ export * from './core/index.js';
27
+ export * from './reader/index.js';
28
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC"}
@@ -0,0 +1,51 @@
1
+ /** The minimal shape the boundary rules read from each top-level node. */
2
+ export interface ChunkNode {
3
+ /** Uppercase tag name for elements, `'#text'` for text nodes. */
4
+ readonly tag: string;
5
+ /** `textContent.length` of this node. */
6
+ readonly chars: number;
7
+ /** Serialized markup — `outerHTML` for elements, escaped text for text nodes. */
8
+ readonly html: string;
9
+ }
10
+ export interface Chunk {
11
+ readonly html: string;
12
+ /** Total characters of text this chunk holds. */
13
+ readonly chars: number;
14
+ /** Number of top-level nodes in this chunk. */
15
+ readonly nodes: number;
16
+ }
17
+ export interface ChunkStats {
18
+ readonly topLevelNodes: number;
19
+ readonly oversizedElements: number;
20
+ readonly largestElementChars: number;
21
+ readonly headingsDeferred: number;
22
+ readonly atomicOversized: number;
23
+ readonly bareTextNodes: number;
24
+ }
25
+ export interface ChunkResult {
26
+ readonly chunks: readonly Chunk[];
27
+ readonly stats: ChunkStats;
28
+ }
29
+ /** Default chunk budget in characters. The whole tradeoff dial; see layout.md. */
30
+ export declare const DEFAULT_CHUNK_CHARS = 8000;
31
+ /**
32
+ * Splits a top-level node list into chunks at flow boundaries, accumulating
33
+ * children until `targetChars` of text is reached.
34
+ *
35
+ * - Split only between top-level (depth-1) children; never descend.
36
+ * - An element larger than the budget is emitted whole as its own chunk (the
37
+ * budget is advisory, not a cap) — descending would put a page break
38
+ * mid-paragraph.
39
+ * - Never end a chunk on a heading or `<hr>`; defer it to the next chunk.
40
+ * - Bare text nodes are glued to the open chunk; whitespace-only ones are
41
+ * dropped by `chunkElement` before this runs.
42
+ */
43
+ export declare function chunkNodes(nodes: readonly ChunkNode[], targetChars?: number): ChunkResult;
44
+ /**
45
+ * Adapts a live DOM element (a section body) into the `ChunkNode` list the
46
+ * boundary rules read, then chunks it. Whitespace-only bare text nodes are
47
+ * dropped here — they carry no block box and would strand against a formatting
48
+ * context they did not come from.
49
+ */
50
+ export declare function chunkElement(body: Element, targetChars?: number): ChunkResult;
51
+ //# sourceMappingURL=chunk.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chunk.d.ts","sourceRoot":"","sources":["../../src/layout/chunk.ts"],"names":[],"mappings":"AAiBA,0EAA0E;AAC1E,MAAM,WAAW,SAAS;IACxB,iEAAiE;IACjE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,yCAAyC;IACzC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,iFAAiF;IACjF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,KAAK;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,iDAAiD;IACjD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,+CAA+C;IAC/C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;IACrC,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;CAChC;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,MAAM,EAAE,SAAS,KAAK,EAAE,CAAC;IAClC,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;CAC5B;AAED,kFAAkF;AAClF,eAAO,MAAM,mBAAmB,OAAO,CAAC;AAWxC;;;;;;;;;;;GAWG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,SAAS,SAAS,EAAE,EAAE,WAAW,SAAsB,GAAG,WAAW,CAmEtG;AAKD;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,OAAO,EAAE,WAAW,SAAsB,GAAG,WAAW,CAiB1F"}
@@ -0,0 +1,131 @@
1
+ /**
2
+ * Chunk-boundary rules for the paginator, derived from real EPUB markup (item8
3
+ * of gutenberg-pride-and-prejudice.epub: 571 top-level blocks, 552 `<p>`, max
4
+ * nesting depth 5), not from theory.
5
+ *
6
+ * A chunk boundary becomes a *forced page break*, because each chunk is laid out
7
+ * as its own multi-column formatting context (layout containment forbids a
8
+ * `content-visibility` box fragmenting across columns). So these rules answer
9
+ * "where is a forced page break acceptable", not merely "where is the DOM
10
+ * splittable".
11
+ *
12
+ * The rules run over a structural view of a top-level node list — `ChunkNode` —
13
+ * rather than the DOM directly, so they are pure and unit-testable under
14
+ * `node:test`. `chunkElement` adapts a real DOM element to that view.
15
+ */
16
+ import { escapeXmlText } from '../core/text.js';
17
+ /** Default chunk budget in characters. The whole tradeoff dial; see layout.md. */
18
+ export const DEFAULT_CHUNK_CHARS = 8000;
19
+ // Splitting *between* these is fine; splitting *inside* one is not — each carries
20
+ // structure (row alignment, list numbering, preformatted whitespace) a second
21
+ // formatting context would restate from scratch.
22
+ const ATOMIC = new Set(['TABLE', 'PRE', 'OL', 'UL', 'DL', 'FIGURE', 'BLOCKQUOTE', 'SVG', 'MATH']);
23
+ // A chunk must never end on one of these: the boundary is a page break, and a
24
+ // heading (or rule) stranded at the foot of a page is the classic orphan.
25
+ const NEVER_LAST = new Set(['H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'HR']);
26
+ /**
27
+ * Splits a top-level node list into chunks at flow boundaries, accumulating
28
+ * children until `targetChars` of text is reached.
29
+ *
30
+ * - Split only between top-level (depth-1) children; never descend.
31
+ * - An element larger than the budget is emitted whole as its own chunk (the
32
+ * budget is advisory, not a cap) — descending would put a page break
33
+ * mid-paragraph.
34
+ * - Never end a chunk on a heading or `<hr>`; defer it to the next chunk.
35
+ * - Bare text nodes are glued to the open chunk; whitespace-only ones are
36
+ * dropped by `chunkElement` before this runs.
37
+ */
38
+ export function chunkNodes(nodes, targetChars = DEFAULT_CHUNK_CHARS) {
39
+ let oversizedElements = 0;
40
+ let largestElementChars = 0;
41
+ let headingsDeferred = 0;
42
+ let atomicOversized = 0;
43
+ let bareTextNodes = 0;
44
+ const chunks = [];
45
+ let current = [];
46
+ let currentChars = 0;
47
+ const flush = () => {
48
+ if (current.length === 0)
49
+ return;
50
+ chunks.push({
51
+ html: current.map((node) => node.html).join(''),
52
+ chars: currentChars,
53
+ nodes: current.length,
54
+ });
55
+ current = [];
56
+ currentChars = 0;
57
+ };
58
+ for (const node of nodes) {
59
+ if (node.tag === '#text')
60
+ bareTextNodes += 1;
61
+ if (node.chars > largestElementChars)
62
+ largestElementChars = node.chars;
63
+ if (node.chars >= targetChars) {
64
+ flush();
65
+ oversizedElements += 1;
66
+ if (ATOMIC.has(node.tag))
67
+ atomicOversized += 1;
68
+ current = [node];
69
+ currentChars = node.chars;
70
+ flush();
71
+ continue;
72
+ }
73
+ if (currentChars > 0 && currentChars + node.chars > targetChars) {
74
+ const deferred = [];
75
+ while (current.length > 1 && NEVER_LAST.has(current[current.length - 1].tag)) {
76
+ const moved = current.pop();
77
+ currentChars -= moved.chars;
78
+ deferred.unshift(moved);
79
+ headingsDeferred += 1;
80
+ }
81
+ flush();
82
+ for (const moved of deferred) {
83
+ current.push(moved);
84
+ currentChars += moved.chars;
85
+ }
86
+ }
87
+ current.push(node);
88
+ currentChars += node.chars;
89
+ }
90
+ flush();
91
+ return {
92
+ chunks,
93
+ stats: {
94
+ topLevelNodes: nodes.length,
95
+ oversizedElements,
96
+ largestElementChars,
97
+ headingsDeferred,
98
+ atomicOversized,
99
+ bareTextNodes,
100
+ },
101
+ };
102
+ }
103
+ const ELEMENT_NODE = 1;
104
+ const TEXT_NODE = 3;
105
+ /**
106
+ * Adapts a live DOM element (a section body) into the `ChunkNode` list the
107
+ * boundary rules read, then chunks it. Whitespace-only bare text nodes are
108
+ * dropped here — they carry no block box and would strand against a formatting
109
+ * context they did not come from.
110
+ */
111
+ export function chunkElement(body, targetChars = DEFAULT_CHUNK_CHARS) {
112
+ const nodes = [];
113
+ for (const node of Array.from(body.childNodes)) {
114
+ if (node.nodeType === ELEMENT_NODE) {
115
+ const element = node;
116
+ nodes.push({
117
+ tag: element.tagName.toUpperCase(),
118
+ chars: element.textContent?.length ?? 0,
119
+ html: element.outerHTML,
120
+ });
121
+ }
122
+ else if (node.nodeType === TEXT_NODE) {
123
+ const text = node.textContent ?? '';
124
+ if (text.trim().length === 0)
125
+ continue;
126
+ nodes.push({ tag: '#text', chars: text.length, html: escapeXmlText(text) });
127
+ }
128
+ }
129
+ return chunkNodes(nodes, targetChars);
130
+ }
131
+ //# sourceMappingURL=chunk.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chunk.js","sourceRoot":"","sources":["../../src/layout/chunk.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,238 @@
1
+ /**
2
+ * The paginator engine: wraps a {@link ContentHost} over a container element and
3
+ * exposes page-oriented navigation, page↔`Position` mapping, and progress on top
4
+ * of the frame's chunked layout. This is the engine the reader facade (M2-4)
5
+ * consumes; it owns no host vocabulary and never fetches or persists.
6
+ *
7
+ * Layout, measurement, chunking, and eviction all live in the frame (Slice 1 —
8
+ * `ContentHost`); this module orchestrates them and bridges page geometry to the
9
+ * headless `Position` model in `src/core`. Core is *called*, never changed: a page
10
+ * maps to a `Position` through `offsetOfPage` → `capturePosition`, and a
11
+ * `Position` maps back through `resolvePosition` → `pageOfOffset`.
12
+ */
13
+ import { type Position, type Section } from '../core/index.ts';
14
+ import { ContentHost, type ContentHostOptions } from '../view/host.ts';
15
+ import type { LayoutMode, PaginateOptions, PaginationState } from '../view/protocol.ts';
16
+ export type { LayoutMode, PaginateOptions, PaginationState } from '../view/protocol.ts';
17
+ /**
18
+ * The parts of {@link PaginateOptions} a caller may set without also supplying
19
+ * the viewport geometry, which the paginator measures from its container. Every
20
+ * field is optional; unset fields fall back to the paginator defaults.
21
+ */
22
+ export interface PaginateRequest {
23
+ readonly mode?: LayoutMode;
24
+ /** Page box width in CSS px. Defaults to the container's client width. */
25
+ readonly pageWidth?: number;
26
+ /** Page box height in CSS px. Defaults to the container's client height. */
27
+ readonly pageHeight?: number;
28
+ readonly columnGap?: number;
29
+ readonly chunkChars?: number;
30
+ readonly windowChunks?: number;
31
+ /** Text columns per page (1 or 2). Defaults to 1. */
32
+ readonly columnCount?: number;
33
+ }
34
+ /**
35
+ * Chapter-local layout state: the current page, the total (estimate or firm),
36
+ * and whether the total has been measured across every chunk yet.
37
+ */
38
+ export interface ChapterProgress {
39
+ readonly mode: LayoutMode;
40
+ /** 0-based page currently shown. */
41
+ readonly page: number;
42
+ /** Total pages — an estimate until {@link firm}. */
43
+ readonly totalPages: number;
44
+ /** True once every chunk is measured; false while {@link totalPages} churns. */
45
+ readonly firm: boolean;
46
+ /** Fraction through the chapter, 0..1. */
47
+ readonly fraction: number;
48
+ readonly realizedChunks: number;
49
+ readonly totalChunks: number;
50
+ }
51
+ /**
52
+ * Where the reader is in the whole book. Section counts come from the facade;
53
+ * only the current section is laid out, so any span across other sections is an
54
+ * even-weight approximation — {@link approximate} says so.
55
+ */
56
+ export interface BookProgress extends ChapterProgress {
57
+ /** 0-based index of the current section in reading order. */
58
+ readonly sectionIndex: number;
59
+ /** Total sections in the book. */
60
+ readonly sectionCount: number;
61
+ /** Fraction through the book, 0..1 — even-weight across sections. */
62
+ readonly bookFraction: number;
63
+ /** Always true: sibling sections are unlaid, so the book span is an estimate. */
64
+ readonly approximate: true;
65
+ }
66
+ export interface PaginatorDiagnostics {
67
+ readonly domNodes: number;
68
+ readonly realizedChunks: number;
69
+ readonly totalChunks: number;
70
+ }
71
+ /** Something went wrong driving the paginator; never a book decoding failure. */
72
+ export declare class PaginatorError extends Error {
73
+ constructor(message: string, options?: ErrorOptions);
74
+ }
75
+ /**
76
+ * Drives chunked pagination of one section at a time inside a sandboxed frame.
77
+ *
78
+ * Lifecycle: construct over a container, {@link paginate} a section, navigate
79
+ * with {@link goToPage}/{@link nextPage}/{@link previousPage}, map pages to
80
+ * `Position`s, and {@link destroy} to tear the frame down. A single instance
81
+ * paginates successive sections in turn; re-paginating replaces the active one.
82
+ */
83
+ export declare class Paginator {
84
+ #private;
85
+ constructor(container: HTMLElement, options?: ContentHostOptions);
86
+ /** The underlying host, for callers that need the raw frame surface. */
87
+ get host(): ContentHost;
88
+ /** The section currently laid out, or `null` before the first {@link paginate}. */
89
+ get section(): Section | null;
90
+ /** The effective options of the current layout, or `null` before {@link paginate}. */
91
+ get options(): PaginateOptions | null;
92
+ /** The last pagination state, or `null` before {@link paginate}. */
93
+ get state(): PaginationState | null;
94
+ /** The current 0-based page. */
95
+ get page(): number;
96
+ /**
97
+ * Chunks and lays out `section` under `request` (merged with the paginator
98
+ * defaults and the container's measured viewport), resets to page 0, and
99
+ * returns the resulting state. The page count starts as an estimate; call
100
+ * {@link refine} to firm it up. Pass `mode: 'scrolled'` for scrolled layout.
101
+ */
102
+ paginate(section: Section, request?: PaginateRequest): Promise<PaginationState>;
103
+ /**
104
+ * Re-lays the current section (after a viewport or typography change) and
105
+ * returns the fresh state. The caller preserving position across the relayout
106
+ * should {@link positionOfPage} before and {@link pageOfPosition} after. Text
107
+ * is unchanged, so its cache survives.
108
+ */
109
+ relayout(): Promise<PaginationState>;
110
+ /**
111
+ * Re-lays the current section in a different mode, preserving the reading
112
+ * position across the switch: it captures a `Position` for the current page,
113
+ * re-paginates, then seeks back to the page that `Position` now resolves to.
114
+ * Returns the new state. A resolution miss (rare — same text, same session)
115
+ * degrades to page 0.
116
+ */
117
+ switchMode(mode: LayoutMode): Promise<PaginationState>;
118
+ /**
119
+ * Re-paginates the current section at the container's *current* size, preserving
120
+ * the reading place. Page geometry is captured once at `paginate` time from the
121
+ * container, so a container that later resizes leaves the frame's content at the
122
+ * old size — it scrolls (shrunk) or leaves a gap (grown); this re-reads the size
123
+ * and re-flows. A no-op (returns `null`) when the size is unchanged or the
124
+ * container is unmeasurable (0×0, e.g. `display:none`), so a `ResizeObserver` may
125
+ * call it on every notification without churn. Mirrors {@link switchMode}: capture
126
+ * a `Position`, re-paginate, seek back (a resolution miss degrades to page 0).
127
+ */
128
+ resize(): Promise<PaginationState | null>;
129
+ /**
130
+ * Drives the estimate toward the true count by re-measuring. In paginated mode
131
+ * the frame refines the count as chunks realize; a `relayout` forces that
132
+ * measurement. Returns the (possibly firm) state. Idempotent once firm.
133
+ */
134
+ refine(): Promise<PaginationState>;
135
+ /** Seeks to a 0-based page, clamping to range. Returns the page actually shown. */
136
+ goToPage(page: number): Promise<number>;
137
+ /** Turns one page forward, clamped at the last page. Returns the new page. */
138
+ nextPage(): Promise<number>;
139
+ /** Turns one page back, clamped at page 0. Returns the new page. */
140
+ previousPage(): Promise<number>;
141
+ /**
142
+ * The `Position` anchored at the start of `page`: page → character offset via
143
+ * `offsetOfPage`, then `capturePosition(text, offset, sectionId)` over the
144
+ * section text. An empty page (offset -1) captures at offset 0.
145
+ */
146
+ positionOfPage(page: number): Promise<Position>;
147
+ /**
148
+ * The `Position` anchored over a frame-supplied UTF-16 offset range on the
149
+ * section text — the bridge behind selection reporting. The frame computes the
150
+ * range against the same tiled section text this measures against, so the
151
+ * `start` offset is captured directly with `capturePosition` (which takes a
152
+ * UTF-16 offset). The quote spans the whole selection (`start`..`end`), not a
153
+ * fixed default, so a host that highlights the returned Position via `decorate`
154
+ * paints the entire selection rather than only its first ~32 graphemes; resolving
155
+ * it back to a page still keys off the anchor's start.
156
+ */
157
+ positionOfOffsetRange(start: number, end: number): Promise<Position>;
158
+ /**
159
+ * The 0-based page painting `position`: `resolvePosition` against the section
160
+ * text yields a character offset, then `pageOfOffset` maps it to a page.
161
+ * Returns -1 when the anchor no longer resolves (the caller degrades softly).
162
+ *
163
+ * Note the offset spaces differ: `resolvePosition` returns a *grapheme* index,
164
+ * while `pageOfOffset` speaks UTF-16 code units. They coincide for BMP text and
165
+ * for a text whose graphemes are all single code units; the conversion below
166
+ * maps grapheme index back to a code-unit offset so multi-unit clusters map
167
+ * correctly.
168
+ */
169
+ pageOfPosition(position: Position): Promise<number>;
170
+ /**
171
+ * The 0-based page painting the element carrying `elementId`, or -1 when no
172
+ * element in the section carries that id (the caller degrades softly). Bridges
173
+ * fragment anchoring: `offsetOfElementId` in the frame yields the element's
174
+ * character offset, then `pageOfOffset` maps it to a page.
175
+ */
176
+ pageOfElementId(elementId: string): Promise<number>;
177
+ /**
178
+ * Draws a decoration over the range `position` resolves to in the current section,
179
+ * and holds the intent so it survives a re-layout. Draw-only: the paginator keeps
180
+ * only the in-memory intent (id → position + class) and never persists it. The
181
+ * `position` is resolved against the frame-measured section text; its resolved
182
+ * grapheme span is converted to a UTF-16 offset range the frame paints over. A
183
+ * soft-miss — the anchor no longer resolves, or belongs to a section other than the
184
+ * one laid out — draws nothing and throws nothing; the intent is still retained so a
185
+ * later re-layout that brings the anchor back into view redraws it.
186
+ */
187
+ decorate(decorationId: string, position: Position, className: string): Promise<void>;
188
+ /** Removes a decoration and drops its intent. A no-op for an unknown id. */
189
+ undecorate(decorationId: string): Promise<void>;
190
+ /** Within-chapter progress: current page, total (estimate/firm), and fraction. */
191
+ chapterProgress(): ChapterProgress;
192
+ /**
193
+ * Within-book progress. The facade supplies the current section's index and the
194
+ * book's section count; only this section is laid out, so the book fraction is
195
+ * an even-weight approximation across sections and {@link BookProgress.approximate}
196
+ * is always true.
197
+ */
198
+ bookProgress(sectionIndex: number, sectionCount: number): BookProgress;
199
+ /**
200
+ * Applies a new appearance theme stylesheet (see `themeStyleSheet`) to the
201
+ * current section, preserving the reading position across the swap. A theme is
202
+ * colours + background only, so chunk geometry is invariant under it: the same
203
+ * markup re-lays out to the same page count and the captured `Position` resolves
204
+ * back to the exact same page — the reader's place is held, not reset to 0 and
205
+ * not drifted, and the text does not reflow. The theme lives in the srcdoc (not
206
+ * over the wire), so it re-assembles the document; because geometry is invariant
207
+ * the anchor page is restored precisely. Before the first `paginate` it only
208
+ * records the theme for the next render.
209
+ *
210
+ * A no-op when the stylesheet is unchanged, so re-issuing the same appearance is
211
+ * free.
212
+ */
213
+ setThemeCss(themeCss: string | undefined): Promise<void>;
214
+ /**
215
+ * Applies a live appearance change that may re-flow the layout — a new
216
+ * appearance stylesheet (font/size/line-height/alignment/hyphenation) and/or a
217
+ * new `columnCount` — preserving the reading position across it. Unlike
218
+ * {@link setThemeCss} (colours only, geometry invariant), a reflowing knob
219
+ * changes chunk geometry, so this reuses the same capture → re-layout → resolve →
220
+ * restore machinery as {@link switchMode}: it captures a `Position` for the
221
+ * current page, re-paginates with the new stylesheet and column count, and seeks
222
+ * back to the page that `Position` now resolves to. A same-text resolution miss
223
+ * degrades to page 0. Before the first `paginate` it only records the stylesheet
224
+ * for the next render. A no-op (same stylesheet, same column count) short-
225
+ * circuits, so re-issuing the same appearance is free.
226
+ */
227
+ applyAppearance(themeCss: string | undefined, geometry?: {
228
+ columnCount?: number;
229
+ columnGap?: number;
230
+ }): Promise<void>;
231
+ /** Frame-side counts, for eviction/memory checks. Eviction itself lives in-frame. */
232
+ diagnostics(): Promise<PaginatorDiagnostics>;
233
+ /** The section's concatenated chunk text, as the frame measures it (cached). */
234
+ sectionText(): Promise<string>;
235
+ /** Tears down the underlying host and frame. Idempotent. */
236
+ destroy(): void;
237
+ }
238
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/layout/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAoC,KAAK,QAAQ,EAAE,KAAK,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAQjG,OAAO,EAAE,WAAW,EAAE,KAAK,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AACvE,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAExF,YAAY,EAAE,UAAU,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AASxF;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,CAAC,EAAE,UAAU,CAAC;IAC3B,0EAA0E;IAC1E,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,4EAA4E;IAC5E,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,qDAAqD;IACrD,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,oCAAoC;IACpC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,oDAAoD;IACpD,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,gFAAgF;IAChF,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,0CAA0C;IAC1C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B;AAED;;;;GAIG;AACH,MAAM,WAAW,YAAa,SAAQ,eAAe;IACnD,6DAA6D;IAC7D,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,kCAAkC;IAClC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,qEAAqE;IACrE,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,iFAAiF;IACjF,QAAQ,CAAC,WAAW,EAAE,IAAI,CAAC;CAC5B;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B;AAED,iFAAiF;AACjF,qBAAa,cAAe,SAAQ,KAAK;IACvC,YAAY,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,EAGlD;CACF;AAED;;;;;;;GAOG;AACH,qBAAa,SAAS;;IAkBpB,YAAY,SAAS,EAAE,WAAW,EAAE,OAAO,GAAE,kBAAuB,EAGnE;IAED,wEAAwE;IACxE,IAAI,IAAI,IAAI,WAAW,CAEtB;IAED,mFAAmF;IACnF,IAAI,OAAO,IAAI,OAAO,GAAG,IAAI,CAE5B;IAED,sFAAsF;IACtF,IAAI,OAAO,IAAI,eAAe,GAAG,IAAI,CAEpC;IAED,oEAAoE;IACpE,IAAI,KAAK,IAAI,eAAe,GAAG,IAAI,CAElC;IAED,gCAAgC;IAChC,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED;;;;;OAKG;IACG,QAAQ,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,GAAE,eAAoB,GAAG,OAAO,CAAC,eAAe,CAAC,CAcxF;IAED;;;;;OAKG;IACG,QAAQ,IAAI,OAAO,CAAC,eAAe,CAAC,CAMzC;IAED;;;;;;OAMG;IACG,UAAU,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,eAAe,CAAC,CAQ3D;IAED;;;;;;;;;OASG;IACG,MAAM,IAAI,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAe9C;IAED;;;;OAIG;IACG,MAAM,IAAI,OAAO,CAAC,eAAe,CAAC,CAIvC;IAED,mFAAmF;IAC7E,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAK5C;IAED,8EAA8E;IACxE,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC,CAEhC;IAED,oEAAoE;IAC9D,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC,CAEpC;IAED;;;;OAIG;IACG,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAKpD;IAED;;;;;;;;;OASG;IACG,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAQzE;IAED;;;;;;;;;;OAUG;IACG,cAAc,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAOxD;IAED;;;;;OAKG;IACG,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAKxD;IAED;;;;;;;;;OASG;IACG,QAAQ,CAAC,YAAY,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAIzF;IAED,4EAA4E;IACtE,UAAU,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAIpD;IAoCD,kFAAkF;IAClF,eAAe,IAAI,eAAe,CAajC;IAED;;;;;OAKG;IACH,YAAY,CAAC,YAAY,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,YAAY,CAKrE;IAED;;;;;;;;;;;;;OAaG;IACG,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAG7D;IAED;;;;;;;;;;;;OAYG;IACG,eAAe,CACnB,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,QAAQ,GAAE;QAAE,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAO,GAC1D,OAAO,CAAC,IAAI,CAAC,CAQf;IAiCD,qFAAqF;IAC/E,WAAW,IAAI,OAAO,CAAC,oBAAoB,CAAC,CAGjD;IAED,gFAAgF;IAC1E,WAAW,IAAI,OAAO,CAAC,MAAM,CAAC,CAGnC;IAED,4DAA4D;IAC5D,OAAO,IAAI,IAAI,CAOd;CAoCF"}