gutterpress 0.11.23-beta.1 → 0.11.23-beta.3
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/README.md +13 -3
- package/dist/api/index.d.ts +5 -5
- package/dist/api/index.js +19 -7
- package/dist/{build-dg8a566j.js → build-fq3mexhy.js} +9 -9
- package/dist/checks/asset/approved-fonts.d.ts +8 -0
- package/dist/checks/asset/extensions.d.ts +1 -1
- package/dist/checks/asset/index.d.ts +1 -0
- package/dist/{cli-e31jshz6.js → cli-5zbdb6mt.js} +296 -65
- package/dist/{cli-ttj95aex.js → cli-7mt0dftw.js} +47 -18
- package/dist/{cli-989eg8jz.js → cli-ah93yyzb.js} +163 -55
- package/dist/{cli-31anr0r9.js → cli-eymdsefg.js} +69 -29
- package/dist/{cli-1fy1pm9d.js → cli-fh685nqs.js} +1 -1
- package/dist/{cli-k087gj0p.js → cli-fsjre61x.js} +123 -12
- package/dist/{cli-s1zt779w.js → cli-q7t04gjt.js} +1 -1
- package/dist/{cli-vhav8g82.js → cli-rybz2dfs.js} +1 -1
- package/dist/cli.js +12 -12
- package/dist/{doctor-g4a42tcz.js → doctor-tg9ht1n3.js} +3 -3
- package/dist/engine/compiler/postprocess.d.ts +3 -0
- package/dist/engine/shared/pdf-inspect.d.ts +33 -0
- package/dist/{engine-jvkcahr1.js → engine-17v87vq5.js} +1 -1
- package/dist/{engine-wgkaqjsc.js → engine-y9fnarfa.js} +2 -2
- package/dist/{ext-w9d5ftcg.js → ext-esz03jz4.js} +27 -10
- package/dist/{extension-restore-5x4mj79d.js → extension-restore-91gy1e28.js} +3 -3
- package/dist/{extension-restore-as0g38p1.js → extension-restore-q70wqah5.js} +5 -5
- package/dist/{gutterpress-agent-d29ry3ak.js → gutterpress-agent-wyryqehx.js} +13 -4
- package/dist/{gutterpress-viewer-ze691rrd.js → gutterpress-viewer-ywkf49q5.js} +38 -153
- package/dist/{index-a4j3xcfp.js → index-67g8f7r4.js} +47 -18
- package/dist/{index-798jt0qc.js → index-d9w3r89w.js} +3 -3
- package/dist/{index-rj5vrhz6.js → index-fntpr44x.js} +321 -66
- package/dist/{index-5x42amh8.js → index-g3te5ey1.js} +2 -1
- package/dist/{index-cw03e9p4.js → index-kw4tbthz.js} +69 -29
- package/dist/{index-fk2kpf2t.js → index-santcs4q.js} +121 -10
- package/dist/{index-c6y0p7jy.js → index-z6vzj3s5.js} +243 -73
- package/dist/index.js +35 -8
- package/dist/lib/check-options.d.ts +70 -0
- package/dist/lib/extension-manager.d.ts +16 -1
- package/dist/lib/extension-scaffold.d.ts +15 -2
- package/dist/lib/extension-specifier.d.ts +8 -1
- package/dist/lib/manifest-config.d.ts +3 -1
- package/dist/lib/manifest-old-spellings.d.ts +32 -9
- package/dist/lib/markdown/gutterpress-css.d.ts +1 -1
- package/dist/lib/markdown/math.d.ts +1 -1
- package/dist/lib/markdown/typography.d.ts +1 -0
- package/dist/lib/page-size.d.ts +12 -4
- package/dist/lib/plugin-vendor.d.ts +6 -0
- package/dist/lib/presets.d.ts +2 -2
- package/dist/lib/root-tokens.d.ts +2 -1
- package/dist/lib/source-provider.d.ts +27 -0
- package/dist/lib/style-resolver.d.ts +2 -1
- package/dist/lib/version-changes.d.ts +22 -6
- package/dist/{manifest.schema-0jgj0jt1.json → manifest.schema-5cm13vr3.json} +215 -5
- package/dist/{new-jtk028rf.js → new-rmfyb7va.js} +22 -15
- package/dist/{plugins-bcbe7xs8.js → plugins-gs21xz5s.js} +2 -2
- package/dist/{plugins-zsm6wv79.js → plugins-tqv1s16f.js} +4 -4
- package/dist/{preflight-cs6mj1d6.js → preflight-bjyeeq0d.js} +9 -9
- package/dist/{preview-d1j1g4qf.js → preview-ke03fk5d.js} +9 -9
- package/dist/{publish-7yw4jyrt.js → publish-wpnz0qng.js} +9 -9
- package/dist/render.js +55 -13
- package/dist/schema/manifest.types.d.ts +45 -7
- package/dist/{source-provider-n7vehh6t.js → source-provider-3g3yrn1f.js} +6 -2
- package/dist/{source-provider-tgzet3j5.js → source-provider-azg9ywhb.js} +6 -2
- package/dist/test-helpers/vocabulary.d.ts +12 -0
- package/dist/{validate-rkcdnzhw.js → validate-zcwykb43.js} +9 -9
- package/package.json +1 -1
- /package/dist/{cli-y28j019d.js → cli-1dha1nxk.js} +0 -0
|
@@ -1032,12 +1032,14 @@ function needsMeasurement(value) {
|
|
|
1032
1032
|
|
|
1033
1033
|
// src/engine/shared/pdf-inspect.ts
|
|
1034
1034
|
import {
|
|
1035
|
+
decodePDFRawStream,
|
|
1035
1036
|
PDFArray,
|
|
1036
1037
|
PDFDict,
|
|
1037
1038
|
PDFDocument,
|
|
1038
1039
|
PDFHexString,
|
|
1039
1040
|
PDFName,
|
|
1040
1041
|
PDFNumber,
|
|
1042
|
+
PDFRawStream,
|
|
1041
1043
|
PDFRef,
|
|
1042
1044
|
PDFString
|
|
1043
1045
|
} from "pdf-lib";
|
|
@@ -1158,6 +1160,52 @@ async function inspectPdf(bytes) {
|
|
|
1158
1160
|
walkOutline(outlines);
|
|
1159
1161
|
return { pageCount: pages.length, boxes, linkTargets, namedDests, outline };
|
|
1160
1162
|
}
|
|
1163
|
+
var PROLOGUE = /^\s*(\d*\.?\d+) 0 0 -\d*\.?\d+ -?\d*\.?\d+ -?\d*\.?\d+ cm/;
|
|
1164
|
+
var CLIP = /(-?\d*\.?\d+) (-?\d*\.?\d+) (\d*\.?\d+) (\d*\.?\d+) re\s+W\*? n\b/g;
|
|
1165
|
+
var UNIFORM = /\bq\s+(\d*\.?\d+) 0 0 \1 (-?\d*\.?\d+) -?\d*\.?\d+ cm/g;
|
|
1166
|
+
var UNSCALED_EPSILON = 0.000001;
|
|
1167
|
+
function printScale(doc) {
|
|
1168
|
+
const readings = new Map;
|
|
1169
|
+
for (const page of doc.getPages()) {
|
|
1170
|
+
const contents = page.node.Contents();
|
|
1171
|
+
const streams = contents instanceof PDFArray ? contents.asArray().map((ref) => doc.context.lookup(ref)) : [contents];
|
|
1172
|
+
let text = "";
|
|
1173
|
+
for (const stream of streams) {
|
|
1174
|
+
if (!(stream instanceof PDFRawStream))
|
|
1175
|
+
continue;
|
|
1176
|
+
try {
|
|
1177
|
+
text += Buffer.from(decodePDFRawStream(stream).decode()).toString("latin1") + `
|
|
1178
|
+
`;
|
|
1179
|
+
} catch {}
|
|
1180
|
+
}
|
|
1181
|
+
const prologue = PROLOGUE.exec(text);
|
|
1182
|
+
if (!prologue)
|
|
1183
|
+
continue;
|
|
1184
|
+
let area;
|
|
1185
|
+
for (const m of text.matchAll(CLIP)) {
|
|
1186
|
+
const size = Number(m[3]) * Number(m[4]);
|
|
1187
|
+
if (!area || size > area.size)
|
|
1188
|
+
area = { x: Number(m[1]), size, end: m.index + m[0].length };
|
|
1189
|
+
}
|
|
1190
|
+
if (!area)
|
|
1191
|
+
continue;
|
|
1192
|
+
UNIFORM.lastIndex = area.end;
|
|
1193
|
+
for (let m;m = UNIFORM.exec(text); ) {
|
|
1194
|
+
if (Math.abs(Number(m[2]) - area.x) > 0.5)
|
|
1195
|
+
continue;
|
|
1196
|
+
const scale = Number(m[1]) * Number(prologue[1]) * 96 / 72;
|
|
1197
|
+
readings.set(scale, (readings.get(scale) ?? 0) + 1);
|
|
1198
|
+
break;
|
|
1199
|
+
}
|
|
1200
|
+
if ([...readings.values()].some((n) => n >= 3))
|
|
1201
|
+
break;
|
|
1202
|
+
}
|
|
1203
|
+
let best = null;
|
|
1204
|
+
for (const [scale, n] of readings)
|
|
1205
|
+
if (best === null || n > readings.get(best))
|
|
1206
|
+
best = scale;
|
|
1207
|
+
return best === null ? null : Math.abs(1 - best) < UNSCALED_EPSILON ? 1 : best;
|
|
1208
|
+
}
|
|
1161
1209
|
|
|
1162
1210
|
// src/lib/embedded-assets.ts
|
|
1163
1211
|
import { existsSync } from "node:fs";
|
|
@@ -1170,7 +1218,7 @@ import { fileURLToPath } from "node:url";
|
|
|
1170
1218
|
var favicon_default = "./favicon-272ga6y0.ico";
|
|
1171
1219
|
|
|
1172
1220
|
// src/assets/manifest.schema.json
|
|
1173
|
-
var manifest_schema_default = "./manifest.schema-
|
|
1221
|
+
var manifest_schema_default = "./manifest.schema-5cm13vr3.json";
|
|
1174
1222
|
|
|
1175
1223
|
// src/assets/preview/scripts/preview-interface.js
|
|
1176
1224
|
var preview_interface_default = "./preview-interface-0xdh0r5b.js";
|
|
@@ -1185,10 +1233,10 @@ var preview_shell_default = "./preview-shell-wk9k3gcd.js";
|
|
|
1185
1233
|
var CGATS21_CRPC1_default = "./CGATS21_CRPC1-g0e3k7kr.icc";
|
|
1186
1234
|
|
|
1187
1235
|
// src/assets/engine/gutterpress-viewer.js
|
|
1188
|
-
var gutterpress_viewer_default = "./gutterpress-viewer-
|
|
1236
|
+
var gutterpress_viewer_default = "./gutterpress-viewer-ywkf49q5.js";
|
|
1189
1237
|
|
|
1190
1238
|
// src/assets/engine/gutterpress-agent.js
|
|
1191
|
-
var gutterpress_agent_default = "./gutterpress-agent-
|
|
1239
|
+
var gutterpress_agent_default = "./gutterpress-agent-wyryqehx.js";
|
|
1192
1240
|
|
|
1193
1241
|
// src/assets/templates/book/manifest.yaml
|
|
1194
1242
|
var manifest_default = "./manifest-mffah3hr.yaml";
|
|
@@ -1483,6 +1531,7 @@ function round(n) {
|
|
|
1483
1531
|
import { PDFDocument as PDFDocument2, PDFName as PDFName2, PDFNumber as PDFNumber2, rgb } from "pdf-lib";
|
|
1484
1532
|
async function postprocess(input, opts) {
|
|
1485
1533
|
const doc = await PDFDocument2.load(input, { updateMetadata: false });
|
|
1534
|
+
const scale = printScale(doc);
|
|
1486
1535
|
const g = opts.geometry;
|
|
1487
1536
|
const inset = g.bleed + g.slug;
|
|
1488
1537
|
const media = [0, 0, g.media.width, g.media.height];
|
|
@@ -1529,7 +1578,8 @@ async function postprocess(input, opts) {
|
|
|
1529
1578
|
bytes,
|
|
1530
1579
|
pageCount: doc.getPageCount(),
|
|
1531
1580
|
padded,
|
|
1532
|
-
boxes: { media, bleed: bleedBox, trim: trimBox }
|
|
1581
|
+
boxes: { media, bleed: bleedBox, trim: trimBox },
|
|
1582
|
+
scale
|
|
1533
1583
|
};
|
|
1534
1584
|
}
|
|
1535
1585
|
function drawCropMarks(page, g) {
|
|
@@ -1820,8 +1870,6 @@ ${pinCss}`);
|
|
|
1820
1870
|
const msg = `${headline}:
|
|
1821
1871
|
${describe(widthOffenders.boxes)}`;
|
|
1822
1872
|
if (opts.allowShrink) {
|
|
1823
|
-
if (scale !== null)
|
|
1824
|
-
diagnose("engine.width.overflow", `${headline}.`);
|
|
1825
1873
|
for (const o of widthOffenders.boxes)
|
|
1826
1874
|
diagnose("engine.width.overflow", `${o.desc} is ${Math.round(o.px)}px wide, past the ${Math.round(widthOffenders.limitPx)}px page content box. ${o.left < -1 ? "Keep it inside the page content box." : "Give it an explicit width that fits."}`);
|
|
1827
1875
|
log(`WARNING: ${msg}`);
|
|
@@ -1837,6 +1885,54 @@ ${describe(widthOffenders.intrinsics)}`;
|
|
|
1837
1885
|
diagnose("engine.width.intrinsic", `${o.desc} has no width set and is naturally wider than the page — if the printed output comes out smaller than your CSS says, give it an explicit width (e.g. width: 100%).`);
|
|
1838
1886
|
log(`WARNING: ${msg}`);
|
|
1839
1887
|
}
|
|
1888
|
+
let unclipped = null;
|
|
1889
|
+
if (!widthOffenders.boxes.length) {
|
|
1890
|
+
const g = tier2.geometry;
|
|
1891
|
+
const ext = g.bleed + g.slug;
|
|
1892
|
+
const contentPx = (name, pseudos) => {
|
|
1893
|
+
const { width, margin } = resolvePage(model, { name: name || undefined, pseudos }).geometry;
|
|
1894
|
+
return (width + 2 * ext - bleedMargin(margin.left, g) - bleedMargin(margin.right, g)) * 96 / 72;
|
|
1895
|
+
};
|
|
1896
|
+
const pages = await page.evaluate(`(() => {
|
|
1897
|
+
const body = document.body;
|
|
1898
|
+
const named = (el) => { const p = getComputedStyle(el).page; return p && p !== "auto" ? p : ""; };
|
|
1899
|
+
if (!body) return { first: "", used: [], reason: "there is no body" };
|
|
1900
|
+
const bs = getComputedStyle(body);
|
|
1901
|
+
const r = body.getBoundingClientRect();
|
|
1902
|
+
if (
|
|
1903
|
+
Math.abs(r.left + parseFloat(bs.borderLeftWidth)) > 0.01 ||
|
|
1904
|
+
Math.abs(r.right - parseFloat(bs.borderRightWidth) - window.innerWidth) > 0.01
|
|
1905
|
+
) return { first: "", used: [], reason: "the body does not span the page content box" };
|
|
1906
|
+
// The first page's name: the root's, overridden down the chain of
|
|
1907
|
+
// first in-flow children (CSS Paged Media's start page value).
|
|
1908
|
+
let first = named(document.documentElement) || named(body);
|
|
1909
|
+
for (let el = body; el; ) {
|
|
1910
|
+
el = [...el.children].find((c) => {
|
|
1911
|
+
const cs = getComputedStyle(c);
|
|
1912
|
+
return cs.display !== "none" && cs.position !== "absolute" && cs.position !== "fixed";
|
|
1913
|
+
});
|
|
1914
|
+
if (el && named(el)) first = named(el);
|
|
1915
|
+
}
|
|
1916
|
+
const used = new Set([""]);
|
|
1917
|
+
for (const el of document.querySelectorAll("*")) used.add(named(el));
|
|
1918
|
+
return { first, used: [...used], reason: "" };
|
|
1919
|
+
})()`);
|
|
1920
|
+
const firstPx = contentPx(pages.first, ["first", "right", "recto"]);
|
|
1921
|
+
const wider = pages.used.find((name) => pseudoContexts.some((pseudos) => contentPx(name, pseudos) > firstPx + 0.01));
|
|
1922
|
+
unclipped = pages.reason || (wider !== undefined ? `${wider ? `the page "${wider}"` : "the unnamed page"} is wider than the first page` : await page.evaluate(`(() => {
|
|
1923
|
+
const hs = getComputedStyle(document.documentElement);
|
|
1924
|
+
const bs = getComputedStyle(document.body);
|
|
1925
|
+
let css;
|
|
1926
|
+
if (hs.overflowX === "visible" && hs.overflowY === "visible")
|
|
1927
|
+
css = "html { overflow-x: clip !important; } " +
|
|
1928
|
+
"body { overflow-x: clip !important; overflow-y: visible !important; }";
|
|
1929
|
+
else if (bs.overflowX === "visible") css = "body { overflow-x: clip !important; }";
|
|
1930
|
+
else return "the body clips its own overflow";
|
|
1931
|
+
window.__gp.addCss("gp-root-clip", css);
|
|
1932
|
+
return "";
|
|
1933
|
+
})()`)) || null;
|
|
1934
|
+
log(`body overflow ${unclipped ? `left as authored: ${unclipped}` : "held to the page content box"}`);
|
|
1935
|
+
}
|
|
1840
1936
|
const rectoDecls = model.breaks.filter(isRectoVersoBreak);
|
|
1841
1937
|
const needsMeasure = tier3Reasons.length > 0 || consumedStrings(model).size > 0 || rectoDecls.length > 0 || model.counterResets.length > 0 || furnitureRoots.length > 0 || sideRoots.length > 0;
|
|
1842
1938
|
let tier = tier2.geometry.bleed > 0 || tier2.geometry.slug > 0 ? 2 : 1;
|
|
@@ -2358,6 +2454,20 @@ ${mapCss}`;
|
|
|
2358
2454
|
author: opts.author
|
|
2359
2455
|
});
|
|
2360
2456
|
log(`postprocess: ${post.pageCount} pages` + (post.padded ? ` (+${post.padded} blank${opts.lastPage ? `; last page: ${opts.lastPage}` : ""})` : ""));
|
|
2457
|
+
{
|
|
2458
|
+
const scale = post.scale;
|
|
2459
|
+
if (scale !== null && scale < 1) {
|
|
2460
|
+
const pct = (scale * 100).toPrecision(6);
|
|
2461
|
+
const overPx = widthOffenders.defaultLimitPx * (1 / scale - 1);
|
|
2462
|
+
diagnose("engine.width.overflow", `This book printed at ${pct}% of its declared size: content reaches about ` + `${overPx < 0.1 ? overPx.toFixed(3) : overPx.toFixed(2)}px past the ` + `${Math.round(widthOffenders.defaultLimitPx)}px page content box, and Chromium shrinks ` + `the WHOLE print to fit it. The preview is not shrunk, so its lines and page ` + `breaks can differ from the PDF's.` + (unclipped ? ` Gutterpress could not hold it at the page content box: ${unclipped}.` : ""));
|
|
2463
|
+
if (!widthOffenders.boxes.length) {
|
|
2464
|
+
const named = await findWidthOffenders(page, model, 2 * (tier2.geometry.bleed + tier2.geometry.slug), sheetViewport, 0);
|
|
2465
|
+
for (const o of named.boxes)
|
|
2466
|
+
diagnose("engine.width.overflow", `${o.desc} reaches ${Math.max(o.px + Math.min(0, o.left) - (o.limit ?? named.limitPx), -o.left).toFixed(2)}px ` + `past the ${Math.round(o.limit ?? named.limitPx)}px page content box. Keep it ` + `inside the page content box.`);
|
|
2467
|
+
}
|
|
2468
|
+
log(`audit: printed at ${pct}% (shrink-to-fit)`);
|
|
2469
|
+
}
|
|
2470
|
+
}
|
|
2361
2471
|
return {
|
|
2362
2472
|
bytes: post.bytes,
|
|
2363
2473
|
tier,
|
|
@@ -2392,7 +2502,7 @@ function shrinkScale(boxes, limitPx) {
|
|
|
2392
2502
|
return null;
|
|
2393
2503
|
return Math.max(1 / MAX_SHRINK, limitPx / maxRight);
|
|
2394
2504
|
}
|
|
2395
|
-
async function findWidthOffenders(page, model, bleedSlugExtensionPt, restoreViewport) {
|
|
2505
|
+
async function findWidthOffenders(page, model, bleedSlugExtensionPt, restoreViewport, tolerancePx = 1) {
|
|
2396
2506
|
const contexts = [
|
|
2397
2507
|
resolvePage(model),
|
|
2398
2508
|
...model.pageNames.filter((n) => !n.startsWith("gp-") || n.startsWith("gp--pin-")).map((n) => resolvePage(model, { name: n }))
|
|
@@ -2418,7 +2528,8 @@ async function findWidthOffenders(page, model, bleedSlugExtensionPt, restoreView
|
|
|
2418
2528
|
mobile: false
|
|
2419
2529
|
});
|
|
2420
2530
|
boxes.push(...JSON.parse(await page.evaluate(`(() => {
|
|
2421
|
-
const
|
|
2531
|
+
const TOL = ${tolerancePx};
|
|
2532
|
+
const LIMIT = Math.max(${widthPx} + TOL, ${Math.ceil(widthPx)});
|
|
2422
2533
|
const NAMED = ${JSON.stringify(namedLimits)};
|
|
2423
2534
|
const DEFAULT_LIMIT = ${defaultLimitPx};
|
|
2424
2535
|
// The page an element lands on: the nearest ancestor with a non-auto
|
|
@@ -2458,10 +2569,10 @@ async function findWidthOffenders(page, model, bleedSlugExtensionPt, restoreView
|
|
|
2458
2569
|
// pulls) AND left-edge protrusion (negative left with an ordinary
|
|
2459
2570
|
// width) — both trigger the same whole-document shrink-to-fit,
|
|
2460
2571
|
// measured: a left bleed alone cost 16%.
|
|
2461
|
-
if (right <= LIMIT && r.width <= LIMIT && r.left >= -
|
|
2572
|
+
if (right <= LIMIT && r.width <= LIMIT && r.left >= -TOL) continue;
|
|
2462
2573
|
// ...but only where it actually escapes its clipping ancestors.
|
|
2463
2574
|
const clip = clipEdges(el).edges;
|
|
2464
|
-
if (Math.min(right, clip.right) <= LIMIT && Math.max(r.left, clip.left) >= -
|
|
2575
|
+
if (Math.min(right, clip.right) <= LIMIT && Math.max(r.left, clip.left) >= -TOL) continue;
|
|
2465
2576
|
let deepest = true;
|
|
2466
2577
|
for (const c of el.children) {
|
|
2467
2578
|
if (c.getBoundingClientRect().width >= r.width - 1) { deepest = false; break; }
|
|
@@ -2498,7 +2609,7 @@ async function findWidthOffenders(page, model, bleedSlugExtensionPt, restoreView
|
|
|
2498
2609
|
const over = el.scrollWidth - el.clientWidth;
|
|
2499
2610
|
// clientWidth is 0 on inline/replaced boxes, where scrollWidth
|
|
2500
2611
|
// carries no overflow information -- skip rather than guess.
|
|
2501
|
-
if (el.clientWidth <= 0 || over <=
|
|
2612
|
+
if (el.clientWidth <= 0 || over <= TOL) continue;
|
|
2502
2613
|
// A descendant assigned to a DIFFERENT page is not overflowing this
|
|
2503
2614
|
// element's page -- it is laid out against its own, wider one. The
|
|
2504
2615
|
// full-bleed art plate is the standard case: it is legitimately
|
|
@@ -2552,7 +2663,7 @@ async function findWidthOffenders(page, model, bleedSlugExtensionPt, restoreView
|
|
|
2552
2663
|
}
|
|
2553
2664
|
return JSON.stringify(out);
|
|
2554
2665
|
})()`));
|
|
2555
|
-
return { limitPx, boxes, intrinsics: replaced };
|
|
2666
|
+
return { limitPx, defaultLimitPx, boxes, intrinsics: replaced };
|
|
2556
2667
|
} finally {
|
|
2557
2668
|
await page.send("Emulation.setDeviceMetricsOverride", restoreViewport);
|
|
2558
2669
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// package.json
|
|
2
2
|
var package_default = {
|
|
3
3
|
name: "gutterpress",
|
|
4
|
-
version: "0.11.23-beta.
|
|
4
|
+
version: "0.11.23-beta.3",
|
|
5
5
|
description: "Markdown-to-PDF converter for professional print layout using a native Chromium print engine and Ghostscript.",
|
|
6
6
|
author: "itlackey",
|
|
7
7
|
license: "MPL-2.0",
|
package/dist/cli.js
CHANGED
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
} from "./cli-d8xjns66.js";
|
|
9
9
|
import {
|
|
10
10
|
package_default
|
|
11
|
-
} from "./cli-
|
|
11
|
+
} from "./cli-q7t04gjt.js";
|
|
12
12
|
import {
|
|
13
13
|
EXIT_CODES
|
|
14
14
|
} from "./cli-46ycxe6r.js";
|
|
@@ -20,14 +20,14 @@ import {
|
|
|
20
20
|
import { defineCommand, parseArgs, runMain } from "citty";
|
|
21
21
|
import { statSync } from "node:fs";
|
|
22
22
|
var SUBCOMMANDS = {
|
|
23
|
-
new: () => import("./new-
|
|
24
|
-
preview: () => import("./preview-
|
|
25
|
-
build: () => import("./build-
|
|
26
|
-
publish: () => import("./publish-
|
|
27
|
-
validate: () => import("./validate-
|
|
28
|
-
preflight: () => import("./preflight-
|
|
29
|
-
doctor: () => import("./doctor-
|
|
30
|
-
ext: () => import("./ext-
|
|
23
|
+
new: () => import("./new-rmfyb7va.js").then((m) => m.default),
|
|
24
|
+
preview: () => import("./preview-ke03fk5d.js").then((m) => m.default),
|
|
25
|
+
build: () => import("./build-fq3mexhy.js").then((m) => m.default),
|
|
26
|
+
publish: () => import("./publish-wpnz0qng.js").then((m) => m.default),
|
|
27
|
+
validate: () => import("./validate-zcwykb43.js").then((m) => m.default),
|
|
28
|
+
preflight: () => import("./preflight-bjyeeq0d.js").then((m) => m.default),
|
|
29
|
+
doctor: () => import("./doctor-tg9ht1n3.js").then((m) => m.default),
|
|
30
|
+
ext: () => import("./ext-esz03jz4.js").then((m) => m.default)
|
|
31
31
|
};
|
|
32
32
|
var VERSION = package_default.version;
|
|
33
33
|
var main = defineCommand({
|
|
@@ -52,7 +52,7 @@ async function preflightRequiredInvocations(rawArgs) {
|
|
|
52
52
|
const [command, ...commandArgs] = rawArgs;
|
|
53
53
|
try {
|
|
54
54
|
if (command === "new") {
|
|
55
|
-
const { newArgs } = await import("./new-
|
|
55
|
+
const { newArgs } = await import("./new-rmfyb7va.js");
|
|
56
56
|
rejectUnknownFlags(commandArgs, newArgs, "new");
|
|
57
57
|
const parsed = parseArgs(commandArgs, {
|
|
58
58
|
...newArgs,
|
|
@@ -64,7 +64,7 @@ async function preflightRequiredInvocations(rawArgs) {
|
|
|
64
64
|
return;
|
|
65
65
|
}
|
|
66
66
|
if (command === "preflight") {
|
|
67
|
-
const { preflightArgs } = await import("./preflight-
|
|
67
|
+
const { preflightArgs } = await import("./preflight-bjyeeq0d.js");
|
|
68
68
|
rejectUnknownFlags(commandArgs, preflightArgs, "preflight");
|
|
69
69
|
const parsed = parseArgs(commandArgs, {
|
|
70
70
|
...preflightArgs,
|
|
@@ -84,7 +84,7 @@ async function preflightRequiredInvocations(rawArgs) {
|
|
|
84
84
|
}
|
|
85
85
|
if (subcommand.startsWith("-"))
|
|
86
86
|
return;
|
|
87
|
-
const { EXT_SUBCOMMANDS, extAddArgs, extRemoveArgs, extEnableArgs, extDisableArgs } = await import("./ext-
|
|
87
|
+
const { EXT_SUBCOMMANDS, extAddArgs, extRemoveArgs, extEnableArgs, extDisableArgs } = await import("./ext-esz03jz4.js");
|
|
88
88
|
if (!EXT_SUBCOMMANDS.includes(subcommand)) {
|
|
89
89
|
throw new UsageError(`gutterpress ext: unknown command "${subcommand}"`);
|
|
90
90
|
}
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getSystemDiagnostics
|
|
3
|
-
} from "./cli-
|
|
3
|
+
} from "./cli-rybz2dfs.js";
|
|
4
4
|
import"./cli-5crpmz42.js";
|
|
5
5
|
import"./cli-asap4t1z.js";
|
|
6
6
|
import {
|
|
7
7
|
log
|
|
8
|
-
} from "./cli-
|
|
8
|
+
} from "./cli-fh685nqs.js";
|
|
9
9
|
import {
|
|
10
10
|
UsageError,
|
|
11
11
|
rejectExtraPositionals,
|
|
12
12
|
rejectUnknownFlags
|
|
13
13
|
} from "./cli-d8xjns66.js";
|
|
14
|
-
import"./cli-
|
|
14
|
+
import"./cli-q7t04gjt.js";
|
|
15
15
|
import"./cli-46ycxe6r.js";
|
|
16
16
|
import"./cli-37x76zdn.js";
|
|
17
17
|
|
|
@@ -27,5 +27,8 @@ export interface PostprocessResult {
|
|
|
27
27
|
bleed: number[];
|
|
28
28
|
trim: number[];
|
|
29
29
|
};
|
|
30
|
+
/** The scale Chromium printed at, read before anything here draws:
|
|
31
|
+
* `printScale` in shared/pdf-inspect.ts (1 = not shrunk). */
|
|
32
|
+
scale: number | null;
|
|
30
33
|
}
|
|
31
34
|
export declare function postprocess(input: Uint8Array, opts: PostprocessOptions): Promise<PostprocessResult>;
|
|
@@ -1,3 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read-side PDF utilities (pdf-lib, pure JS).
|
|
3
|
+
*
|
|
4
|
+
* Three jobs:
|
|
5
|
+
* 1. Verification: page count, page boxes, embedded fonts — the evidence the
|
|
6
|
+
* tests assert on.
|
|
7
|
+
* 2. Tier 3 measurement channel (§8): harvest Chromium's own link annotations
|
|
8
|
+
* and document outline to learn "which page is element X on", with no text
|
|
9
|
+
* heuristics.
|
|
10
|
+
* 3. The print scale: whether Chromium's shrink-to-fit scaled the page area
|
|
11
|
+
* ({@link printScale}).
|
|
12
|
+
*/
|
|
13
|
+
import { PDFDocument } from "pdf-lib";
|
|
1
14
|
export interface PageBoxes {
|
|
2
15
|
media: number[];
|
|
3
16
|
crop?: number[];
|
|
@@ -18,3 +31,23 @@ export interface PdfFacts {
|
|
|
18
31
|
}>;
|
|
19
32
|
}
|
|
20
33
|
export declare function inspectPdf(bytes: Uint8Array): Promise<PdfFacts>;
|
|
34
|
+
/**
|
|
35
|
+
* The scale Chromium printed the page area at: 1 when it laid the document
|
|
36
|
+
* out at the page content box's own width, below 1 when print shrink-to-fit
|
|
37
|
+
* scaled the whole document down because something reached past that box
|
|
38
|
+
* (ENGINE.md §9). `null` when no page shows the transform — a reader that
|
|
39
|
+
* cannot find it makes no claim. Pass Chromium's own print, before anything
|
|
40
|
+
* redraws its pages.
|
|
41
|
+
*
|
|
42
|
+
* Read off the content streams rather than predicted from element widths.
|
|
43
|
+
* Each page draws its page box (background, margin boxes) under an unscaled
|
|
44
|
+
* `3.125 0 0 3.125 0 0 cm` — CSS px to 300-per-inch device units — then clips
|
|
45
|
+
* to the page area, its largest clip, and draws the page area's content
|
|
46
|
+
* under `s 0 0 s x y cm`, where x is the clip's own left edge and s is 3.125
|
|
47
|
+
* times the shrink. An element with a CSS transform or its own clip draws
|
|
48
|
+
* under other matrices, so one page can read wrong; Chromium applies one
|
|
49
|
+
* factor to the whole document, so the first reading three pages agree on
|
|
50
|
+
* (or the most common, in a shorter document) is the answer. The prologue
|
|
51
|
+
* fixes the device resolution: the scale is s × prologue × 96/72.
|
|
52
|
+
*/
|
|
53
|
+
export declare function printScale(doc: PDFDocument): number | null;
|
|
@@ -2,28 +2,30 @@ import {
|
|
|
2
2
|
importExtensionFromFile,
|
|
3
3
|
importExtensionFromUrl,
|
|
4
4
|
searchNpmExtensions
|
|
5
|
-
} from "./cli-
|
|
6
|
-
import"./cli-
|
|
5
|
+
} from "./cli-ah93yyzb.js";
|
|
6
|
+
import"./cli-rybz2dfs.js";
|
|
7
7
|
import"./cli-ht1bcqdd.js";
|
|
8
|
-
import"./cli-
|
|
8
|
+
import"./cli-fsjre61x.js";
|
|
9
9
|
import"./cli-5crpmz42.js";
|
|
10
10
|
import"./cli-eyyggect.js";
|
|
11
11
|
import"./cli-asap4t1z.js";
|
|
12
|
-
import"./cli-
|
|
12
|
+
import"./cli-eymdsefg.js";
|
|
13
13
|
import"./cli-v5mp7a6q.js";
|
|
14
14
|
import {
|
|
15
|
+
BUILT_IN_LOOKS,
|
|
16
|
+
addBuiltInStyleSet,
|
|
15
17
|
addExtension,
|
|
16
18
|
checkExtensionUpdates,
|
|
17
19
|
listProjectExtensions,
|
|
18
20
|
removeExtension,
|
|
19
21
|
setExtensionEnabled,
|
|
20
22
|
updateExtensions
|
|
21
|
-
} from "./cli-
|
|
23
|
+
} from "./cli-5zbdb6mt.js";
|
|
22
24
|
import {
|
|
23
25
|
isPathSpecifier,
|
|
24
26
|
parseExtensionSpecifier
|
|
25
|
-
} from "./cli-
|
|
26
|
-
import"./cli-
|
|
27
|
+
} from "./cli-7mt0dftw.js";
|
|
28
|
+
import"./cli-fh685nqs.js";
|
|
27
29
|
import {
|
|
28
30
|
UsageError,
|
|
29
31
|
exitForUsage,
|
|
@@ -31,12 +33,12 @@ import {
|
|
|
31
33
|
rejectUnknownFlags,
|
|
32
34
|
resolveProjectDir
|
|
33
35
|
} from "./cli-d8xjns66.js";
|
|
34
|
-
import"./cli-
|
|
36
|
+
import"./cli-q7t04gjt.js";
|
|
35
37
|
import"./cli-65gy8ask.js";
|
|
36
38
|
import {
|
|
37
39
|
EXIT_CODES
|
|
38
40
|
} from "./cli-46ycxe6r.js";
|
|
39
|
-
import"./cli-
|
|
41
|
+
import"./cli-1dha1nxk.js";
|
|
40
42
|
import"./cli-37x76zdn.js";
|
|
41
43
|
|
|
42
44
|
// src/commands/ext.ts
|
|
@@ -65,6 +67,11 @@ var extAddArgs = {
|
|
|
65
67
|
type: "string",
|
|
66
68
|
description: "Named module export to use as the plugin function (npm and path extensions only)",
|
|
67
69
|
required: false
|
|
70
|
+
},
|
|
71
|
+
look: {
|
|
72
|
+
type: "boolean",
|
|
73
|
+
description: "Treat SOURCE as a built-in look (clean-book, zine, technical-doc, academic): copy it into extensions/ as your own files and list the copy",
|
|
74
|
+
required: false
|
|
68
75
|
}
|
|
69
76
|
};
|
|
70
77
|
var extRemoveArgs = { specifier: specifierArg, dir: dirArg };
|
|
@@ -202,7 +209,13 @@ var add = defineCommand({
|
|
|
202
209
|
if (typeof args.export === "string" && !exportName) {
|
|
203
210
|
throw new UsageError("gutterpress ext add: --export requires a non-empty name");
|
|
204
211
|
}
|
|
205
|
-
if (
|
|
212
|
+
if (args.look && !BUILT_IN_LOOKS.includes(source)) {
|
|
213
|
+
throw new UsageError(`gutterpress ext add --look: unknown built-in look "${source}" (one of: ${BUILT_IN_LOOKS.join(", ")})`);
|
|
214
|
+
}
|
|
215
|
+
if (args.look && exportName) {
|
|
216
|
+
throw new UsageError("gutterpress ext add --look: a look takes no --export");
|
|
217
|
+
}
|
|
218
|
+
if (!args.look && !isUrl && !existing) {
|
|
206
219
|
try {
|
|
207
220
|
if (path.isAbsolute(source) || isPathSpecifier(source)) {
|
|
208
221
|
throw new Error(`source not found: ${candidate}`);
|
|
@@ -216,6 +229,10 @@ var add = defineCommand({
|
|
|
216
229
|
exitForUsage(error);
|
|
217
230
|
}
|
|
218
231
|
try {
|
|
232
|
+
if (args.look) {
|
|
233
|
+
printAdded(await addBuiltInStyleSet(projectDir, source), projectDir);
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
219
236
|
if (isUrl) {
|
|
220
237
|
const { entry: entry2, warnings } = await importExtensionFromUrl(projectDir, source);
|
|
221
238
|
printAdded(entry2, projectDir, warnings.map((w) => w.message));
|
|
@@ -3,10 +3,10 @@ import {
|
|
|
3
3
|
restoreForCommand,
|
|
4
4
|
restoreOfflineMessage,
|
|
5
5
|
restorePinnedExtensions
|
|
6
|
-
} from "./index-
|
|
7
|
-
import"./index-
|
|
6
|
+
} from "./index-fntpr44x.js";
|
|
7
|
+
import"./index-67g8f7r4.js";
|
|
8
8
|
import"./index-tayzfr9c.js";
|
|
9
|
-
import"./index-
|
|
9
|
+
import"./index-g3te5ey1.js";
|
|
10
10
|
import"./index-37x76zdn.js";
|
|
11
11
|
export {
|
|
12
12
|
restorePinnedExtensions,
|
|
@@ -3,14 +3,14 @@ import {
|
|
|
3
3
|
restoreForCommand,
|
|
4
4
|
restoreOfflineMessage,
|
|
5
5
|
restorePinnedExtensions
|
|
6
|
-
} from "./cli-
|
|
7
|
-
import"./cli-
|
|
8
|
-
import"./cli-
|
|
6
|
+
} from "./cli-5zbdb6mt.js";
|
|
7
|
+
import"./cli-7mt0dftw.js";
|
|
8
|
+
import"./cli-fh685nqs.js";
|
|
9
9
|
import"./cli-d8xjns66.js";
|
|
10
|
-
import"./cli-
|
|
10
|
+
import"./cli-q7t04gjt.js";
|
|
11
11
|
import"./cli-65gy8ask.js";
|
|
12
12
|
import"./cli-46ycxe6r.js";
|
|
13
|
-
import"./cli-
|
|
13
|
+
import"./cli-1dha1nxk.js";
|
|
14
14
|
import"./cli-37x76zdn.js";
|
|
15
15
|
export {
|
|
16
16
|
restorePinnedExtensions,
|
|
@@ -59,6 +59,7 @@
|
|
|
59
59
|
});
|
|
60
60
|
|
|
61
61
|
// src/engine/shared/synthesis.ts
|
|
62
|
+
var RECTO_VERSO_VALUES = /^(right|recto|left|verso)$/;
|
|
62
63
|
var WHICH_VALUES = new Set(["first", "start", "last", "first-except"]);
|
|
63
64
|
var LEADER_RE = /\uE000([^\uE001]*)\uE001/;
|
|
64
65
|
function leaderFillCount(gapPx, gluePx) {
|
|
@@ -422,7 +423,8 @@
|
|
|
422
423
|
return out;
|
|
423
424
|
}
|
|
424
425
|
function forcedBreakSites(decls) {
|
|
425
|
-
const
|
|
426
|
+
const found = [];
|
|
427
|
+
const seen = new Set;
|
|
426
428
|
for (const d of decls) {
|
|
427
429
|
let els = [];
|
|
428
430
|
try {
|
|
@@ -430,10 +432,17 @@
|
|
|
430
432
|
} catch {
|
|
431
433
|
continue;
|
|
432
434
|
}
|
|
433
|
-
for (const el of els)
|
|
434
|
-
|
|
435
|
+
for (const el of els) {
|
|
436
|
+
const id = ensureAnchor(el);
|
|
437
|
+
const value = getComputedStyle(el).breakBefore;
|
|
438
|
+
if (seen.has(el) || !RECTO_VERSO_VALUES.test(value))
|
|
439
|
+
continue;
|
|
440
|
+
seen.add(el);
|
|
441
|
+
found.push({ el, id, prop: d.prop, value, selector: d.selector });
|
|
442
|
+
}
|
|
435
443
|
}
|
|
436
|
-
|
|
444
|
+
found.sort((a, b) => a.el.compareDocumentPosition(b.el) & Node.DOCUMENT_POSITION_FOLLOWING ? -1 : 1);
|
|
445
|
+
return found.map(({ el: _el, ...site }) => site);
|
|
437
446
|
}
|
|
438
447
|
function counterResetSites(resets) {
|
|
439
448
|
const out = [];
|