@cairn-tool/cairn 3.1.0 → 3.3.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 (91) hide show
  1. package/README.md +74 -28
  2. package/dist/agent/audit/index.d.ts +6 -6
  3. package/dist/agent/audit/index.js +6 -17
  4. package/dist/agent/audit/index.js.map +1 -1
  5. package/dist/archive/run.d.ts +14 -7
  6. package/dist/archive/run.js +4 -1
  7. package/dist/archive/run.js.map +1 -1
  8. package/dist/archive/sets.d.ts +26 -1
  9. package/dist/archive/sets.js +108 -0
  10. package/dist/archive/sets.js.map +1 -1
  11. package/dist/atomic-write.d.ts +22 -0
  12. package/dist/atomic-write.js +42 -0
  13. package/dist/atomic-write.js.map +1 -0
  14. package/dist/binary-kind.d.ts +13 -0
  15. package/dist/binary-kind.js +25 -0
  16. package/dist/binary-kind.js.map +1 -0
  17. package/dist/cli.js +48 -0
  18. package/dist/cli.js.map +1 -1
  19. package/dist/commands/archive.js +11 -5
  20. package/dist/commands/archive.js.map +1 -1
  21. package/dist/commands/jira.js +1 -21
  22. package/dist/commands/jira.js.map +1 -1
  23. package/dist/commands/pdf.d.ts +29 -0
  24. package/dist/commands/pdf.js +345 -0
  25. package/dist/commands/pdf.js.map +1 -0
  26. package/dist/contract/registry.js +65 -1
  27. package/dist/contract/registry.js.map +1 -1
  28. package/dist/contract/schemas/index.js +2 -0
  29. package/dist/contract/schemas/index.js.map +1 -1
  30. package/dist/contract/schemas/pdf.d.ts +2 -0
  31. package/dist/contract/schemas/pdf.js +292 -0
  32. package/dist/contract/schemas/pdf.js.map +1 -0
  33. package/dist/jira/adf/to-markdown.js +2 -32
  34. package/dist/jira/adf/to-markdown.js.map +1 -1
  35. package/dist/markdown-stringify.d.ts +35 -0
  36. package/dist/markdown-stringify.js +44 -0
  37. package/dist/markdown-stringify.js.map +1 -0
  38. package/dist/pdf/attachments.d.ts +50 -0
  39. package/dist/pdf/attachments.js +229 -0
  40. package/dist/pdf/attachments.js.map +1 -0
  41. package/dist/pdf/diagnostics.d.ts +110 -0
  42. package/dist/pdf/diagnostics.js +137 -0
  43. package/dist/pdf/diagnostics.js.map +1 -0
  44. package/dist/pdf/document.d.ts +159 -0
  45. package/dist/pdf/document.js +272 -0
  46. package/dist/pdf/document.js.map +1 -0
  47. package/dist/pdf/forms.d.ts +9 -0
  48. package/dist/pdf/forms.js +101 -0
  49. package/dist/pdf/forms.js.map +1 -0
  50. package/dist/pdf/inspect.d.ts +42 -0
  51. package/dist/pdf/inspect.js +232 -0
  52. package/dist/pdf/inspect.js.map +1 -0
  53. package/dist/pdf/layout.d.ts +78 -0
  54. package/dist/pdf/layout.js +524 -0
  55. package/dist/pdf/layout.js.map +1 -0
  56. package/dist/pdf/outline.d.ts +30 -0
  57. package/dist/pdf/outline.js +127 -0
  58. package/dist/pdf/outline.js.map +1 -0
  59. package/dist/pdf/read.d.ts +62 -0
  60. package/dist/pdf/read.js +193 -0
  61. package/dist/pdf/read.js.map +1 -0
  62. package/dist/pdf/struct.d.ts +35 -0
  63. package/dist/pdf/struct.js +226 -0
  64. package/dist/pdf/struct.js.map +1 -0
  65. package/dist/pdf/text.d.ts +71 -0
  66. package/dist/pdf/text.js +166 -0
  67. package/dist/pdf/text.js.map +1 -0
  68. package/dist/pdf/to-markdown.d.ts +22 -0
  69. package/dist/pdf/to-markdown.js +289 -0
  70. package/dist/pdf/to-markdown.js.map +1 -0
  71. package/dist/pdf/types.d.ts +205 -0
  72. package/dist/pdf/types.js +2 -0
  73. package/dist/pdf/types.js.map +1 -0
  74. package/dist/pdf/validate.d.ts +51 -0
  75. package/dist/pdf/validate.js +136 -0
  76. package/dist/pdf/validate.js.map +1 -0
  77. package/dist/serve/pdf-tools.d.ts +2 -0
  78. package/dist/serve/pdf-tools.js +196 -0
  79. package/dist/serve/pdf-tools.js.map +1 -0
  80. package/dist/serve/tools.d.ts +2 -17
  81. package/dist/serve/tools.js +4 -0
  82. package/dist/serve/tools.js.map +1 -1
  83. package/dist/serve/types.d.ts +22 -0
  84. package/dist/serve/types.js +2 -0
  85. package/dist/serve/types.js.map +1 -0
  86. package/dist/usage/providers/cursor.d.ts +2 -0
  87. package/dist/usage/providers/cursor.js +570 -0
  88. package/dist/usage/providers/cursor.js.map +1 -0
  89. package/dist/usage/providers/index.js +2 -0
  90. package/dist/usage/providers/index.js.map +1 -1
  91. package/package.json +2 -1
@@ -0,0 +1,524 @@
1
+ import { CODES } from "./diagnostics.js";
2
+ import { round2 } from "./text.js";
3
+ const byPosition = (a, b) => a.page - b.page || a.y - b.y || a.x - b.x || a.index - b.index;
4
+ /**
5
+ * The value occurring most often.
6
+ *
7
+ * The tie-break direction is a real decision, not a detail. For a *size* the
8
+ * larger value wins, because a tie between body and caption should read as the
9
+ * body. For a *spacing* the smaller wins: line spacing within a paragraph is the
10
+ * tightest recurring gap, and heading-to-body gaps tie with it on any document
11
+ * short enough that body lines do not outnumber them — at which point picking
12
+ * the larger elects the heading gap as the body leading and no paragraph ever
13
+ * breaks.
14
+ */
15
+ function mode(values, prefer = "largest") {
16
+ const counts = new Map();
17
+ for (const value of values)
18
+ counts.set(value, (counts.get(value) ?? 0) + 1);
19
+ let best = 0;
20
+ let bestCount = -1;
21
+ for (const [value, count] of counts) {
22
+ const wins = count > bestCount ||
23
+ (count === bestCount && (prefer === "largest" ? value > best : value < best));
24
+ if (wins) {
25
+ best = value;
26
+ bestCount = count;
27
+ }
28
+ }
29
+ return best;
30
+ }
31
+ /**
32
+ * Splits out runs no axis-aligned heuristic can place.
33
+ *
34
+ * Text at an arbitrary angle and vertical writing are excluded rather than
35
+ * folded in at the wrong position, and reported. Every stage after this may
36
+ * assume upright, left-to-right runs.
37
+ */
38
+ export function normalize(runs, sink) {
39
+ const body = [];
40
+ let dropped = 0;
41
+ for (const run of runs) {
42
+ if (run.angle === null || run.angle !== 0 || run.vertical) {
43
+ dropped += 1;
44
+ sink.add({
45
+ code: CODES.rotatedTextDropped,
46
+ quality: "unsupported",
47
+ message: "Rotated or vertical text cannot be placed in reading order and was excluded",
48
+ page: run.page,
49
+ });
50
+ continue;
51
+ }
52
+ body.push(run);
53
+ }
54
+ return { body, dropped };
55
+ }
56
+ /* ------------------------------------------------------------------ *
57
+ * Stage 2 — running headers and footers
58
+ * ------------------------------------------------------------------ */
59
+ /** Digits masked, so `Page 3 of 40` and `Page 4 of 40` land in one bucket. */
60
+ function artifactKey(run) {
61
+ return `${Math.round(run.y / 2)}|${run.text.trim().replace(/\d+/g, "#")}`;
62
+ }
63
+ /**
64
+ * Removes text that repeats at the same height on most pages.
65
+ *
66
+ * Requires at least four pages: below that, repetition is not evidence. A bucket
67
+ * that repeats but is *not* near an edge is left alone — that is a section title
68
+ * or a watermark, and dropping it would delete content.
69
+ */
70
+ export function removeArtifacts(runs, pageCount, pageHeight, sink) {
71
+ if (pageCount < 4)
72
+ return runs;
73
+ const pagesFor = new Map();
74
+ for (const run of runs) {
75
+ const key = artifactKey(run);
76
+ const seen = pagesFor.get(key);
77
+ if (seen)
78
+ seen.add(run.page);
79
+ else
80
+ pagesFor.set(key, new Set([run.page]));
81
+ }
82
+ const edge = pageHeight * 0.12;
83
+ const artifacts = new Set();
84
+ for (const [key, pages] of pagesFor) {
85
+ // 40%, not a majority. A bound book alternates its running heads between
86
+ // verso and recto — the title on one side, the chapter on the other — so
87
+ // each appears on about half the pages and a majority threshold catches
88
+ // neither. Content that genuinely repeats at a fixed height within the top
89
+ // or bottom eighth of two pages in five is a running head by any reading.
90
+ if (pages.size / pageCount < 0.4)
91
+ continue;
92
+ const y = Number(key.split("|")[0]) * 2;
93
+ if (y > edge && y < pageHeight - edge)
94
+ continue;
95
+ artifacts.add(key);
96
+ }
97
+ if (artifacts.size === 0)
98
+ return runs;
99
+ const kept = runs.filter((run) => !artifacts.has(artifactKey(run)));
100
+ sink.add({
101
+ code: CODES.artifactsRemoved,
102
+ quality: "exact",
103
+ message: `Removed ${runs.length - kept.length} running header or footer run(s) repeating across pages`,
104
+ });
105
+ return kept;
106
+ }
107
+ /* ------------------------------------------------------------------ *
108
+ * Stage 3 — columns
109
+ * ------------------------------------------------------------------ */
110
+ /**
111
+ * Splits a page's runs into columns, or reports that it could not.
112
+ *
113
+ * Reading a two-column page top to bottom interleaves the columns into text that
114
+ * reads like prose and is not — a degradation indistinguishable from success, so
115
+ * refusing to look is not the safe option. Looking, with a reported failure
116
+ * mode, is.
117
+ *
118
+ * A gutter is a vertical band at least 3% of the page wide containing no run and
119
+ * spanning at least 70% of the content's height. A candidate is rejected when
120
+ * the resulting sides differ by more than 6:1, which is a hanging indent or a
121
+ * figure rather than a gutter.
122
+ */
123
+ export function splitColumns(runs, pageWidth, sink, page) {
124
+ if (runs.length < 8)
125
+ return [runs];
126
+ const minGutter = pageWidth * 0.03;
127
+ const left = Math.min(...runs.map((run) => run.x));
128
+ const right = Math.max(...runs.map((run) => run.x + run.width));
129
+ const top = Math.min(...runs.map((run) => run.y));
130
+ const bottom = Math.max(...runs.map((run) => run.y));
131
+ const span = bottom - top;
132
+ // Sample the content band; a column boundary is an x with no ink either side.
133
+ const step = Math.max(1, Math.floor((right - left) / 200));
134
+ const occupied = [];
135
+ for (let x = left; x <= right; x += step) {
136
+ const index = Math.floor((x - left) / step);
137
+ occupied[index] = runs.some((run) => run.x <= x && run.x + run.width >= x);
138
+ }
139
+ const gutters = [];
140
+ let runStart = -1;
141
+ for (let index = 0; index < occupied.length; index += 1) {
142
+ if (!occupied[index]) {
143
+ if (runStart === -1)
144
+ runStart = index;
145
+ continue;
146
+ }
147
+ if (runStart !== -1) {
148
+ const width = (index - runStart) * step;
149
+ if (width >= minGutter && runStart > 0)
150
+ gutters.push(left + (runStart + (index - runStart) / 2) * step);
151
+ runStart = -1;
152
+ }
153
+ }
154
+ if (gutters.length === 0 || gutters.length > 2) {
155
+ if (gutters.length > 2)
156
+ sink.add({
157
+ code: CODES.readingOrderUncertain,
158
+ quality: "approximate",
159
+ message: `Found ${gutters.length + 1} candidate columns; the page was read top to bottom instead`,
160
+ page,
161
+ });
162
+ return [runs];
163
+ }
164
+ const bounds = [left - 1, ...gutters, right + 1];
165
+ const columns = [];
166
+ for (let index = 0; index < bounds.length - 1; index += 1)
167
+ columns.push(runs.filter((run) => run.x > bounds[index] && run.x <= bounds[index + 1]));
168
+ const sizes = columns.map((column) => column.length).filter((count) => count > 0);
169
+ if (sizes.length < 2 || Math.max(...sizes) / Math.min(...sizes) > 6 || span <= 0)
170
+ return [runs];
171
+ sink.add({
172
+ code: CODES.columnsDetected,
173
+ quality: "exact",
174
+ message: `Read as ${columns.length} columns`,
175
+ page,
176
+ });
177
+ return columns.filter((column) => column.length > 0);
178
+ }
179
+ /* ------------------------------------------------------------------ *
180
+ * Stage 4 — lines
181
+ * ------------------------------------------------------------------ */
182
+ /** Groups runs into lines and records the wide gaps within each. */
183
+ export function buildLines(runs) {
184
+ if (runs.length === 0)
185
+ return [];
186
+ const ordered = [...runs].sort(byPosition);
187
+ const groups = [[ordered[0]]];
188
+ for (const run of ordered.slice(1)) {
189
+ const group = groups[groups.length - 1];
190
+ const previous = group[group.length - 1];
191
+ const tolerance = Math.max(previous.size, run.size) * 0.35;
192
+ if (run.page === previous.page && Math.abs(run.y - previous.y) <= tolerance)
193
+ group.push(run);
194
+ else
195
+ groups.push([run]);
196
+ }
197
+ return groups.map((group) => {
198
+ const sorted = [...group].sort((a, b) => a.x - b.x || a.index - b.index);
199
+ const gaps = [];
200
+ let text = sorted[0].text;
201
+ for (let index = 1; index < sorted.length; index += 1) {
202
+ const previous = sorted[index - 1];
203
+ const run = sorted[index];
204
+ const gap = run.x - (previous.x + previous.width);
205
+ if (gap > previous.size * 1.5)
206
+ gaps.push(round2(run.x));
207
+ const needsSpace = gap > previous.size * 0.25 && !/\s$/.test(text) && !/^\s/.test(run.text);
208
+ text += needsSpace ? ` ${run.text}` : run.text;
209
+ }
210
+ return {
211
+ page: sorted[0].page,
212
+ y: sorted[0].y,
213
+ runs: sorted,
214
+ text: text.trim(),
215
+ x: round2(sorted[0].x),
216
+ size: mode(sorted.map((run) => run.size)),
217
+ bold: sorted.every((run) => run.bold),
218
+ gaps,
219
+ };
220
+ });
221
+ }
222
+ /* ------------------------------------------------------------------ *
223
+ * Stages 5-9 — blocks
224
+ * ------------------------------------------------------------------ */
225
+ const BULLETS = /^[•‣▪◦·⁃∙*–—-]\s*$/;
226
+ const ORDINAL = /^\(?(\d{1,3}|[ivxlcdm]{1,7}|[A-Za-z])[.)]$/;
227
+ /**
228
+ * A line whose first run is a list marker.
229
+ *
230
+ * `rest` is the line's text with the marker consumed. Keeping it would render
231
+ * `- • The first finding`, because remark-stringify supplies the bullet and the
232
+ * source's own marker is then duplicated inside the item.
233
+ */
234
+ function markerOf(line) {
235
+ const first = line.runs[0];
236
+ if (!first)
237
+ return null;
238
+ const token = first.text.trim();
239
+ const withoutFirstRun = () => line.runs
240
+ .slice(1)
241
+ .map((run) => run.text)
242
+ .join(" ")
243
+ .replace(/\s+/g, " ")
244
+ .trim();
245
+ if (line.runs.length >= 2) {
246
+ const next = line.runs[1];
247
+ if (BULLETS.test(token))
248
+ return { ordered: false, textX: next.x, rest: withoutFirstRun() };
249
+ if (ORDINAL.test(token))
250
+ return { ordered: true, textX: next.x, rest: withoutFirstRun() };
251
+ }
252
+ const inline = /^([•‣▪◦·*]|\(?\d{1,3}[.)])\s+/.exec(line.text);
253
+ if (inline)
254
+ return {
255
+ ordered: /\d/.test(inline[1]),
256
+ textX: line.x + first.size,
257
+ rest: line.text.slice(inline[0].length).trim(),
258
+ };
259
+ return null;
260
+ }
261
+ /** Tokens seen hyphenated mid-line, which must not be rejoined at a line end. */
262
+ function realHyphenations(lines) {
263
+ const seen = new Set();
264
+ for (const line of lines)
265
+ for (const match of line.text.matchAll(/(\w+-\w+)/g))
266
+ seen.add(match[1].toLowerCase());
267
+ return seen;
268
+ }
269
+ /**
270
+ * Turns one document's pages into blocks.
271
+ *
272
+ * Column splitting, line grouping, and paragraph breaking are per page; the
273
+ * modal body size and the heading size ranking are computed across the whole
274
+ * document, because a per-page ranking makes heading levels drift between pages
275
+ * of the same document.
276
+ */
277
+ export function blocksFromLayout(pages, sink, options = {}) {
278
+ const allRuns = pages.flatMap((page) => page.runs);
279
+ if (allRuns.length === 0)
280
+ return [];
281
+ const { body } = normalize(allRuns, sink);
282
+ if (body.length === 0)
283
+ return [];
284
+ const pageHeight = mode(pages.map((page) => page.height));
285
+ const kept = removeArtifacts(body, pages.length, pageHeight, sink);
286
+ // Weighted by characters, not by run count: a document full of tiny footnote
287
+ // runs would otherwise elect the footnote size as the body size.
288
+ const weights = new Map();
289
+ for (const run of kept) {
290
+ const bucket = Math.round(run.size * 4) / 4;
291
+ weights.set(bucket, (weights.get(bucket) ?? 0) + run.text.length);
292
+ }
293
+ let bodySize = 0;
294
+ let bodyWeight = -1;
295
+ for (const [size, weight] of weights)
296
+ if (weight > bodyWeight || (weight === bodyWeight && size > bodySize)) {
297
+ bodySize = size;
298
+ bodyWeight = weight;
299
+ }
300
+ const lines = [];
301
+ for (const page of pages) {
302
+ const pageRuns = kept.filter((run) => run.page === page.page);
303
+ if (pageRuns.length === 0)
304
+ continue;
305
+ for (const column of splitColumns(pageRuns, page.width, sink, page.page))
306
+ lines.push(...buildLines(column));
307
+ }
308
+ if (lines.length === 0)
309
+ return [];
310
+ // Heading level by rank, never by ratio. A ratio produces H1/H3/H6 with no H2,
311
+ // which markdownlint flags — and a converted document has to lint clean where
312
+ // it lands.
313
+ const candidateSizes = [
314
+ ...new Set(lines
315
+ .filter((line) => line.size >= bodySize * 1.15 || (line.bold && line.size >= bodySize))
316
+ .map((line) => line.size)),
317
+ ].sort((a, b) => b - a);
318
+ const levelFor = new Map();
319
+ candidateSizes.forEach((size, index) => levelFor.set(size, Math.min(index + 1, 6)));
320
+ if (candidateSizes.length > 6)
321
+ sink.add({
322
+ code: CODES.headingLevelsCollapsed,
323
+ quality: "approximate",
324
+ message: `${candidateSizes.length} distinct heading sizes; the smallest were collapsed to level 6`,
325
+ });
326
+ const hyphenated = realHyphenations(lines);
327
+ // `bodySize` is bucketed to a quarter point and a line's size is a mode of
328
+ // 2-dp run sizes, so `line.size === bodySize` is almost never true on a real
329
+ // document — a 10.91pt body never equals its own 11.0 bucket. Comparing with
330
+ // the bucket width instead is what keeps the two statistics below from being
331
+ // computed over an empty set, which is silent and makes every paragraph split
332
+ // after one line.
333
+ const isBody = (line) => Math.abs(line.size - bodySize) <= 0.25;
334
+ // Measured only between consecutive *body-size* lines. A heading-to-body gap is
335
+ // not line spacing, and on any document with more headings than paragraphs it
336
+ // outnumbers the real leading and elects itself — after which no paragraph ever
337
+ // breaks, because every real gap is smaller than the "modal" one.
338
+ const spacings = [];
339
+ for (let index = 1; index < lines.length; index += 1) {
340
+ const previous = lines[index - 1];
341
+ const line = lines[index];
342
+ if (line.page !== previous.page)
343
+ continue;
344
+ if (!isBody(line) || !isBody(previous))
345
+ continue;
346
+ const delta = line.y - previous.y;
347
+ if (delta > 0)
348
+ spacings.push(Math.round(delta * 2) / 2);
349
+ }
350
+ const modalSpacing = mode(spacings, "smallest") || bodySize * 1.2;
351
+ // The body's left margin, taken over body-size lines. A first-line indent is
352
+ // measured *against this*, not against the previous line: in a typeset
353
+ // document the first line of a paragraph is the indented one, so comparing
354
+ // neighbours makes every continuation line — which sits back at the margin —
355
+ // look like a fresh paragraph, and every paragraph splits after one line.
356
+ const modalLeft = mode(lines.filter(isBody).map((line) => Math.round(line.x)), "smallest");
357
+ const blocks = [];
358
+ let rejoined = 0;
359
+ let paragraph = [];
360
+ let listItems = [];
361
+ let listOrdered = false;
362
+ const provenance = (quality, pageNumbers) => ({
363
+ path: "geometric",
364
+ quality,
365
+ pages: [...new Set(pageNumbers)].sort((a, b) => a - b),
366
+ });
367
+ const spansFrom = (group) => {
368
+ let text = "";
369
+ for (const line of group) {
370
+ if (!text) {
371
+ text = line.text;
372
+ continue;
373
+ }
374
+ const match = /(\w+)-$/.exec(text);
375
+ if (match && /^[a-z]/.test(line.text) && !hyphenated.has(`${match[1].toLowerCase()}-`)) {
376
+ text = `${text.slice(0, -1)}${line.text}`;
377
+ rejoined += 1;
378
+ }
379
+ else
380
+ text += ` ${line.text}`;
381
+ }
382
+ const bold = group.every((line) => line.bold);
383
+ return text ? [{ text, bold, italic: false, code: false }] : [];
384
+ };
385
+ const flushParagraph = () => {
386
+ if (paragraph.length === 0)
387
+ return;
388
+ const spans = spansFrom(paragraph);
389
+ if (spans.length)
390
+ blocks.push({
391
+ kind: "paragraph",
392
+ spans,
393
+ children: [],
394
+ provenance: provenance("approximate", paragraph.map((line) => line.page)),
395
+ });
396
+ paragraph = [];
397
+ };
398
+ const flushList = () => {
399
+ if (listItems.length === 0)
400
+ return;
401
+ blocks.push({
402
+ kind: "list",
403
+ ordered: listOrdered,
404
+ spans: [],
405
+ children: listItems.map((item) => ({
406
+ kind: "listItem",
407
+ spans: spansFrom(item.lines),
408
+ children: [],
409
+ provenance: provenance("approximate", item.lines.map((line) => line.page)),
410
+ })),
411
+ provenance: provenance("approximate", listItems.flatMap((item) => item.lines.map((l) => l.page))),
412
+ });
413
+ if (listOrdered)
414
+ sink.add({
415
+ code: CODES.listNumberingLost,
416
+ quality: "exact",
417
+ message: "An ordered list's original numbering is renumbered on output",
418
+ });
419
+ listItems = [];
420
+ };
421
+ const flushAll = () => {
422
+ flushParagraph();
423
+ flushList();
424
+ };
425
+ // Tabular runs are detected, flattened, and reported — never reconstructed.
426
+ // A geometric table gets merged cells, wrapped cell text, and rules drawn as
427
+ // vector paths wrong, and produces a confidently wrong table the consumer
428
+ // cannot tell from a right one. Real tables come from the structure tree.
429
+ const tabular = new Set();
430
+ for (let index = 0; index + 2 < lines.length; index += 1) {
431
+ const window = [lines[index], lines[index + 1], lines[index + 2]];
432
+ if (!window.every((line) => line.gaps.length >= 2))
433
+ continue;
434
+ const first = window[0].gaps;
435
+ const consistent = window.every((line) => line.gaps.every((gap) => first.some((reference) => Math.abs(gap - reference) <= 2)));
436
+ if (consistent)
437
+ for (let offset = 0; offset < 3; offset += 1)
438
+ tabular.add(index + offset);
439
+ }
440
+ if (tabular.size > 0)
441
+ sink.add({
442
+ code: CODES.tableFlattened,
443
+ quality: "approximate",
444
+ message: `Tabular content on ${tabular.size} line(s) was emitted as one paragraph per row`,
445
+ remediation: "A geometric table cannot be reconstructed faithfully; only a tagged PDF's tables are.",
446
+ });
447
+ lines.forEach((line, index) => {
448
+ const previous = index > 0 ? lines[index - 1] : null;
449
+ const level = levelFor.get(line.size);
450
+ const marker = markerOf(line);
451
+ const isHeading = level !== undefined &&
452
+ line.runs.length > 0 &&
453
+ !marker &&
454
+ line.text.length > 0 &&
455
+ line.size > bodySize;
456
+ if (isHeading) {
457
+ flushAll();
458
+ const pinned = options.headingLevels?.get(line.text);
459
+ blocks.push({
460
+ kind: "heading",
461
+ level: Math.min(pinned ?? level, 6),
462
+ // Not bold: the heading level already carries the emphasis, and wrapping
463
+ // the text in `**` as well renders `# **Title**`.
464
+ spans: [{ text: line.text, bold: false, italic: false, code: false }],
465
+ children: [],
466
+ provenance: provenance(pinned ? "exact" : "approximate", [line.page]),
467
+ });
468
+ return;
469
+ }
470
+ if (marker) {
471
+ flushParagraph();
472
+ if (listItems.length === 0)
473
+ listOrdered = marker.ordered;
474
+ listItems.push({ lines: [{ ...line, text: marker.rest }], ordered: marker.ordered });
475
+ return;
476
+ }
477
+ if (listItems.length > 0) {
478
+ const last = listItems[listItems.length - 1];
479
+ const itemX = last.lines[0].runs[1]?.x ?? last.lines[0].x;
480
+ if (previous && line.page === previous.page && Math.abs(line.x - itemX) <= 1.5) {
481
+ last.lines.push(line);
482
+ return;
483
+ }
484
+ flushList();
485
+ }
486
+ if (previous) {
487
+ const delta = line.page === previous.page ? line.y - previous.y : 0;
488
+ // Indented *past* the margin, which is what a paragraph's first line does.
489
+ // A line returning to the margin is a continuation and must not break.
490
+ const indented = paragraph.length > 0 && line.x > modalLeft + Math.max(2, bodySize * 0.4);
491
+ // A tolerance, not equality: a line carrying an inline code span or a
492
+ // symbol run has a slightly different modal size and is not a new block.
493
+ const fontChanged = Math.abs(line.size - previous.size) > 0.5;
494
+ const shortAndFinal = /[.!?]["')\]]?$/.test(previous.text) && previous.text.length < line.text.length * 0.85;
495
+ // All four are needed: leading alone misses indent-led paragraphs, indent
496
+ // alone splits hanging indents, and terminal punctuation alone splits at
497
+ // every abbreviation.
498
+ if (delta > modalSpacing * 1.35 || indented || fontChanged || (delta > 0 && shortAndFinal))
499
+ flushParagraph();
500
+ else if (line.page !== previous.page && paragraph.length > 0) {
501
+ const ends = /[.!?]["')\]]?$/.test(previous.text);
502
+ if (ends)
503
+ flushParagraph();
504
+ else
505
+ sink.add({
506
+ code: CODES.paragraphSpansPages,
507
+ quality: "exact",
508
+ message: `A paragraph continuing across the page ${previous.page} boundary was rejoined`,
509
+ page: line.page,
510
+ });
511
+ }
512
+ }
513
+ paragraph.push(line);
514
+ });
515
+ flushAll();
516
+ if (rejoined > 0)
517
+ sink.add({
518
+ code: CODES.hyphenationRejoined,
519
+ quality: "exact",
520
+ message: `Rejoined ${rejoined} word(s) split by a line-end hyphen`,
521
+ });
522
+ return blocks;
523
+ }
524
+ //# sourceMappingURL=layout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layout.js","sourceRoot":"","sources":["../../src/pdf/layout.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ import type { OpenDocument } from "./document.js";
2
+ import type { PdfDiagnostic, PdfOutlineEntry } from "./types.js";
3
+ /**
4
+ * The outline is attacker-shaped structure and the walk is recursive, so it is
5
+ * bounded for the same reason the ADF reader bounds nesting depth: a stack
6
+ * overflow with no diagnostic is the wrong failure for input off a network.
7
+ */
8
+ export declare const MAX_OUTLINE_DEPTH = 64;
9
+ export interface OutlineResult {
10
+ outline: PdfOutlineEntry[];
11
+ diagnostics: PdfDiagnostic[];
12
+ /** Normalized title to level, for `layout.ts` to pin heading levels against. */
13
+ headingLevels: Map<string, number>;
14
+ }
15
+ /**
16
+ * Reads the declared outline and resolves each destination to a page.
17
+ *
18
+ * The outline a document declares, never one inferred from its text: a document
19
+ * with no `/Outlines` returns an empty tree and exits 0, which is an answer
20
+ * rather than a failure.
21
+ *
22
+ * URLs are recorded, never followed — no fetch, no HEAD, no DNS. `unsafeUrl` is
23
+ * deliberately not surfaced as `url`: pdf.js populates `url` only when the
24
+ * scheme passed its own validation, and putting a rejected `javascript:` or
25
+ * `file:` URI into a field named as though it were clickable would be a
26
+ * misrepresentation.
27
+ */
28
+ export declare function readOutline(handle: OpenDocument): Promise<OutlineResult>;
29
+ /** Renders the tree for the human-facing streams, two spaces per level. */
30
+ export declare function formatOutline(entries: PdfOutlineEntry[]): string;