@ai-matrx/print 0.7.0 → 0.7.1

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/document.js CHANGED
@@ -1397,9 +1397,24 @@ var courierCanDraw = (s) => {
1397
1397
  }
1398
1398
  return true;
1399
1399
  };
1400
+ var NO_GLYPH = /[\p{Extended_Pictographic}\u{1F1E6}-\u{1F1FF}\u200D\uFE0F\u20E3]/gu;
1401
+ function drawable(text, c) {
1402
+ if (!NO_GLYPH.test(text)) return text;
1403
+ NO_GLYPH.lastIndex = 0;
1404
+ if (!c.glyphs.announced) {
1405
+ c.glyphs.announced = true;
1406
+ c.tree.notices.push({
1407
+ code: "glyph-substituted",
1408
+ message: "Emoji and pictographs were left out of the PDF: its fonts cannot draw them (Word, EPUB and HTML keep them).",
1409
+ remedy: "Use words or plain symbols instead of emoji if they must appear in the PDF."
1410
+ });
1411
+ }
1412
+ return text.replace(NO_GLYPH, "").replace(/ {2,}/g, " ");
1413
+ }
1400
1414
  function runs2(nodes, c, st = {}) {
1401
1415
  const out = [];
1402
- const base = (text) => {
1416
+ const base = (raw) => {
1417
+ const text = drawable(raw, c);
1403
1418
  const r = { text };
1404
1419
  if (st.bold) r.bold = true;
1405
1420
  if (st.italics) r.italics = true;
@@ -1476,6 +1491,8 @@ var capNode = (cap, c, where) => ({
1476
1491
  text: [{ text: cap.label, bold: true, color: COLOR.heading }, ...cap.children.length ? [": ", ...runs2(cap.children, c)] : []],
1477
1492
  style: "caption",
1478
1493
  id: cap.id ? `${cap.kind}:${cap.id}` : void 0,
1494
+ // A caption above its table is never the last line on a page.
1495
+ ...where === "above" ? { headlineLevel: 9 } : {},
1479
1496
  margin: where === "above" ? [0, 0, 0, 4] : [0, 4, 0, 0]
1480
1497
  });
1481
1498
  function estimateLines(text, c) {
@@ -1498,13 +1515,12 @@ function taskItem(checked, content, c) {
1498
1515
  columnGap: 2
1499
1516
  };
1500
1517
  }
1501
- function gluable(b) {
1518
+ function gluable(b, c) {
1502
1519
  if (!b) return false;
1503
- if (b.type === "paragraph" || b.type === "figure" || b.type === "rule") return true;
1504
- if (b.type === "code") return b.value.split("\n").length <= 45;
1505
- if (b.type === "table") return b.rows.length <= 20;
1506
- if (b.type === "list") return b.items.length <= 12;
1507
- if (b.type === "blockquote") return b.children.length <= 4;
1520
+ if (b.type === "paragraph") return estimateLines(plain(b.children), c) <= 5;
1521
+ if (b.type === "figure" || b.type === "rule") return true;
1522
+ if (b.type === "list")
1523
+ return b.items.length <= 4 && b.items.every((i) => i.children.length === 1 && i.children[0]?.type === "paragraph");
1508
1524
  return false;
1509
1525
  }
1510
1526
  function blocks2(list, c) {
@@ -1513,7 +1529,7 @@ function blocks2(list, c) {
1513
1529
  for (let i = 0; i < list.length; i++) {
1514
1530
  const b = list[i];
1515
1531
  let node = block2(b, c);
1516
- if (node && b.type === "heading" && gluable(list[i + 1])) {
1532
+ if (node && b.type === "heading" && gluable(list[i + 1], c)) {
1517
1533
  const next = block2(list[i + 1], c);
1518
1534
  if (next) {
1519
1535
  node = { stack: [node, next], unbreakable: true };
@@ -1583,7 +1599,7 @@ function block2(b, c) {
1583
1599
  const lines = b.value.replace(/\n$/, "").split("\n");
1584
1600
  const size = c.s.fontSize * 0.8;
1585
1601
  const stack = lines.map((l) => {
1586
- const t2 = l.replace(/\t/g, " ") || " ";
1602
+ const t2 = drawable(l.replace(/\t/g, " "), c) || " ";
1587
1603
  return courierCanDraw(t2) ? { text: t2, font: "Courier", fontSize: size, preserveLeadingSpaces: true } : { text: t2, fontSize: size, preserveLeadingSpaces: true };
1588
1604
  });
1589
1605
  return {
@@ -1599,8 +1615,9 @@ function block2(b, c) {
1599
1615
  paddingBottom: () => 6
1600
1616
  },
1601
1617
  margin: [0, 0, 0, 8],
1602
- // Keep a block that fits on one page together.
1603
- unbreakable: lines.length <= 45
1618
+ // Keep a block that fits on one page together (30 lines fits even a
1619
+ // landscape page; a taller unbreakable block would be dropped).
1620
+ unbreakable: lines.length <= 30
1604
1621
  };
1605
1622
  }
1606
1623
  case "table": {
@@ -1634,7 +1651,7 @@ function block2(b, c) {
1634
1651
  const stack = [];
1635
1652
  if (b.caption) stack.push(capNode(b.caption, c, "above"));
1636
1653
  stack.push(table);
1637
- return { stack, margin: [0, 2, 0, 10], unbreakable: b.rows.length <= 20 };
1654
+ return { stack, margin: [0, 2, 0, 10] };
1638
1655
  }
1639
1656
  case "figure": {
1640
1657
  const img = c.images?.get(b.url);
@@ -1720,6 +1737,7 @@ function buildPdfDefinition(tree, images, pageCountSink) {
1720
1737
  const headings = [];
1721
1738
  for (const sec of tree.sections) for (const b of sec.blocks) if (b.type === "heading") headings.push(b.level);
1722
1739
  const c = {
1740
+ glyphs: { announced: false },
1723
1741
  tree,
1724
1742
  images,
1725
1743
  s,
@@ -1841,7 +1859,7 @@ async function documentToPdf(tree, images) {
1841
1859
  }
1842
1860
  async function headingPages(tree, images) {
1843
1861
  const pdfMake = await loadPdfMake();
1844
- const def = buildPdfDefinition(tree, images);
1862
+ const def = buildPdfDefinition({ ...tree, notices: [] }, images);
1845
1863
  await pdfMake.createPdf(def).getBuffer();
1846
1864
  const want = new Set(tree.toc.map((e) => e.id));
1847
1865
  const pages = /* @__PURE__ */ new Map();