gutterpress 0.11.18-alpha.2 → 0.11.18-alpha.4
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/api/index.js +2 -2
- package/dist/{build-se062swz.js → build-63nwjhzf.js} +4 -4
- package/dist/{cli-qp6dtsh3.js → cli-36v78t6w.js} +1 -1
- package/dist/{cli-161z4n0s.js → cli-5x7s8bap.js} +2 -2
- package/dist/{cli-yqpnksaa.js → cli-88hddvbz.js} +1 -1
- package/dist/{cli-0w3961p5.js → cli-dmcy8kay.js} +400 -44
- package/dist/cli.js +12 -12
- package/dist/{doctor-tkbdx8c1.js → doctor-n1cwrwx2.js} +2 -2
- package/dist/{engine-jkf4pxz9.js → engine-6zfj0jte.js} +1 -1
- package/dist/{engine-7gfr16t8.js → engine-zw8626be.js} +2 -2
- package/dist/{ext-kg8m8vda.js → ext-ddfjfcg4.js} +4 -4
- package/dist/{gutterpress-viewer-spq1ge52.js → gutterpress-viewer-k4mpqjh0.js} +57 -29
- package/dist/{index-bb2d1ev8.js → index-1ergtg60.js} +401 -45
- package/dist/{index-t3zxy69d.js → index-jt552wtf.js} +2 -2
- package/dist/{index-3x23by5j.js → index-qbd874dh.js} +1 -1
- package/dist/index.js +3 -3
- package/dist/lib/markdown/block-names.d.ts +82 -0
- package/dist/lib/markdown/renderer.d.ts +3 -2
- package/dist/lib/markdown/table-align.d.ts +32 -0
- package/dist/lib/printsafe.d.ts +1 -0
- package/dist/lib/unknown-classes.d.ts +12 -0
- package/dist/{manifest.schema-8m82f37q.json → manifest.schema-5pzhscqh.json} +1 -1
- package/dist/{new-w7q0n21v.js → new-ede0f1nm.js} +4 -4
- package/dist/{preflight-m54qsjs7.js → preflight-b6c3k3qt.js} +4 -4
- package/dist/{preview-bg3wxqxc.js → preview-y2dxxbrk.js} +4 -4
- package/dist/{publish-waps63wf.js → publish-n60n0hm1.js} +4 -4
- package/dist/render.js +199 -28
- package/dist/{validate-c9d8d656.js → validate-2c7sfyxn.js} +4 -4
- package/package.json +1 -1
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
getAssetsDir,
|
|
10
10
|
lastPageMode,
|
|
11
11
|
parseSize
|
|
12
|
-
} from "./index-
|
|
12
|
+
} from "./index-jt552wtf.js";
|
|
13
13
|
import {
|
|
14
14
|
INSTALL_HINTS,
|
|
15
15
|
execCapture,
|
|
@@ -786,10 +786,11 @@ function parseMarkerLine(line, declaredWords) {
|
|
|
786
786
|
const kind = head.slice(1);
|
|
787
787
|
if (!KNOWN_KINDS.includes(kind) && !(declaredWords && declaredWords.has(kind)))
|
|
788
788
|
return null;
|
|
789
|
-
if (kind === "
|
|
789
|
+
if (kind === "continue" || kind.startsWith("end-")) {
|
|
790
790
|
return { kind, name: null, attrs: {} };
|
|
791
791
|
}
|
|
792
|
-
const
|
|
792
|
+
const isBreak = kind === "page-break" || kind === "column-break";
|
|
793
|
+
const body = isBreak ? tokens.slice(1).filter((token) => !isBareToken(token)) : tokens.slice(1);
|
|
793
794
|
const hasExplicitAttrsOrShorthand = body.some((token) => token.includes("=") || token.startsWith(".") || token.startsWith("#"));
|
|
794
795
|
const bareTokens = body.filter(isBareToken);
|
|
795
796
|
let name = null;
|
|
@@ -857,6 +858,8 @@ function parseMarkerLine(line, declaredWords) {
|
|
|
857
858
|
}
|
|
858
859
|
if (classes.length)
|
|
859
860
|
attrs.class = classes.join(" ");
|
|
861
|
+
if (isBreak)
|
|
862
|
+
return { kind, name: null, attrs };
|
|
860
863
|
const marker = { kind, name, attrs };
|
|
861
864
|
if (hasAmbiguousBareToken)
|
|
862
865
|
marker.__ambiguousBareToken = true;
|
|
@@ -1039,6 +1042,11 @@ function attachDataAttrs(token, kind, name, attrs) {
|
|
|
1039
1042
|
token.attrSet(k.startsWith("data-") ? k : `data-${k}`, v);
|
|
1040
1043
|
}
|
|
1041
1044
|
}
|
|
1045
|
+
function attachBreak(token, baseClass, attrs = {}) {
|
|
1046
|
+
addClasses(token, baseClass, attrs.class);
|
|
1047
|
+
token.attrSet("aria-hidden", "true");
|
|
1048
|
+
attachDataAttrs(token, "break", null, attrs);
|
|
1049
|
+
}
|
|
1042
1050
|
var DECLARED_NAME_RE = /^[a-z][a-z0-9-]*$/;
|
|
1043
1051
|
function validateDeclaredMarkerName(name, pluginName) {
|
|
1044
1052
|
if (!DECLARED_NAME_RE.test(name)) {
|
|
@@ -1595,7 +1603,11 @@ function plugin(md, pluginOptions = {}) {
|
|
|
1595
1603
|
attachDataAttrs(t, component.kind, component.variant, meta.attrs || {});
|
|
1596
1604
|
else
|
|
1597
1605
|
attachDataAttrs(t, "section", meta.name, meta.attrs || {});
|
|
1598
|
-
t.meta =
|
|
1606
|
+
t.meta = {
|
|
1607
|
+
line: meta.__line,
|
|
1608
|
+
...component || {},
|
|
1609
|
+
...meta.__continued ? { continued: true } : {}
|
|
1610
|
+
};
|
|
1599
1611
|
stack.open({
|
|
1600
1612
|
kind: "section",
|
|
1601
1613
|
classes: meta.attrs && meta.attrs.class || "",
|
|
@@ -1693,12 +1705,12 @@ function plugin(md, pluginOptions = {}) {
|
|
|
1693
1705
|
drainDeclaredFrames(keep);
|
|
1694
1706
|
const contMeta = {
|
|
1695
1707
|
name: section.meta.name,
|
|
1696
|
-
attrs: { ...section.meta.attrs || {} }
|
|
1708
|
+
attrs: { ...section.meta.attrs || {} },
|
|
1709
|
+
__continued: true
|
|
1697
1710
|
};
|
|
1698
|
-
|
|
1711
|
+
delete contMeta.attrs.id;
|
|
1712
|
+
if (section.meta.component)
|
|
1699
1713
|
contMeta.__component = section.meta.component;
|
|
1700
|
-
contMeta.__continued = true;
|
|
1701
|
-
}
|
|
1702
1714
|
contMeta.__line = line;
|
|
1703
1715
|
const cls = (contMeta.attrs.class || "").split(/\s+/).filter(Boolean);
|
|
1704
1716
|
if (!cls.includes("gp-continued"))
|
|
@@ -1711,16 +1723,14 @@ function plugin(md, pluginOptions = {}) {
|
|
|
1711
1723
|
if (kind === "page-break") {
|
|
1712
1724
|
const t = new state.Token("layout_page_break", "div", 0);
|
|
1713
1725
|
t.meta = { line };
|
|
1714
|
-
t
|
|
1715
|
-
t.attrSet("aria-hidden", "true");
|
|
1726
|
+
attachBreak(t, "gp-page-break", meta.attrs);
|
|
1716
1727
|
out.push(t);
|
|
1717
1728
|
continue;
|
|
1718
1729
|
}
|
|
1719
1730
|
if (kind === "column-break") {
|
|
1720
1731
|
const t = new state.Token("layout_column_break", "div", 0);
|
|
1721
1732
|
t.meta = { line };
|
|
1722
|
-
t
|
|
1723
|
-
t.attrSet("aria-hidden", "true");
|
|
1733
|
+
attachBreak(t, "gp-column-break", meta.attrs);
|
|
1724
1734
|
out.push(t);
|
|
1725
1735
|
continue;
|
|
1726
1736
|
}
|
|
@@ -1784,24 +1794,10 @@ function plugin(md, pluginOptions = {}) {
|
|
|
1784
1794
|
}
|
|
1785
1795
|
});
|
|
1786
1796
|
}
|
|
1787
|
-
|
|
1788
|
-
const cls = tokens[idx].attrGet("class") || "gp-page-break";
|
|
1789
|
-
const rangeAttr = tokens[idx].attrGet("data-source-range");
|
|
1790
|
-
const rangeHtml = rangeAttr ? ` data-source-range="${escapeAttr(rangeAttr)}"` : "";
|
|
1791
|
-
const chapterAttr = tokens[idx].attrGet("data-chapter-src");
|
|
1792
|
-
const chapterHtml = chapterAttr ? ` data-chapter-src="${escapeAttr(chapterAttr)}"` : "";
|
|
1793
|
-
return `<div class="${escapeAttr(cls)}" aria-hidden="true"${rangeHtml}${chapterHtml}></div>
|
|
1797
|
+
const renderBreak = (tokens, idx, options2, env, self) => `<div${self.renderAttrs(tokens[idx])}></div>
|
|
1794
1798
|
`;
|
|
1795
|
-
|
|
1796
|
-
md.renderer.rules.layout_column_break =
|
|
1797
|
-
const cls = tokens[idx].attrGet("class") || "gp-column-break";
|
|
1798
|
-
const rangeAttr = tokens[idx].attrGet("data-source-range");
|
|
1799
|
-
const rangeHtml = rangeAttr ? ` data-source-range="${escapeAttr(rangeAttr)}"` : "";
|
|
1800
|
-
const chapterAttr = tokens[idx].attrGet("data-chapter-src");
|
|
1801
|
-
const chapterHtml = chapterAttr ? ` data-chapter-src="${escapeAttr(chapterAttr)}"` : "";
|
|
1802
|
-
return `<div class="${escapeAttr(cls)}" aria-hidden="true"${rangeHtml}${chapterHtml}></div>
|
|
1803
|
-
`;
|
|
1804
|
-
};
|
|
1799
|
+
md.renderer.rules.layout_page_break = renderBreak;
|
|
1800
|
+
md.renderer.rules.layout_column_break = renderBreak;
|
|
1805
1801
|
md.renderer.rules.layout_marker = () => "";
|
|
1806
1802
|
}
|
|
1807
1803
|
var NO_MARGIN_BOXES = [
|
|
@@ -2153,6 +2149,27 @@ var GP_CLASSES = new Set([
|
|
|
2153
2149
|
"gp-flush"
|
|
2154
2150
|
]);
|
|
2155
2151
|
|
|
2152
|
+
// src/lib/markdown/table-align.ts
|
|
2153
|
+
var ALIGN = /^text-align:(left|center|right)$/;
|
|
2154
|
+
function gpTableAlign(md) {
|
|
2155
|
+
md.core.ruler.after("block", "gp_table_align", (state) => {
|
|
2156
|
+
for (const token of state.tokens) {
|
|
2157
|
+
if (token.type !== "th_open" && token.type !== "td_open")
|
|
2158
|
+
continue;
|
|
2159
|
+
const match = ALIGN.exec(token.attrGet("style") ?? "");
|
|
2160
|
+
if (!match)
|
|
2161
|
+
continue;
|
|
2162
|
+
token.attrs = (token.attrs ?? []).filter(([key]) => key !== "style");
|
|
2163
|
+
token.attrSet("data-align", match[1]);
|
|
2164
|
+
}
|
|
2165
|
+
});
|
|
2166
|
+
}
|
|
2167
|
+
var TABLE_ALIGN_CSS = `
|
|
2168
|
+
th[data-align="left"], td[data-align="left"] { text-align: left; }
|
|
2169
|
+
th[data-align="center"], td[data-align="center"] { text-align: center; }
|
|
2170
|
+
th[data-align="right"], td[data-align="right"] { text-align: right; }
|
|
2171
|
+
`;
|
|
2172
|
+
|
|
2156
2173
|
// src/lib/markdown/renderer.ts
|
|
2157
2174
|
import MarkdownIt from "markdown-it";
|
|
2158
2175
|
|
|
@@ -2321,6 +2338,156 @@ function gpPinScope(md) {
|
|
|
2321
2338
|
});
|
|
2322
2339
|
}
|
|
2323
2340
|
|
|
2341
|
+
// src/lib/slug.ts
|
|
2342
|
+
function slugify(name, fallback = "") {
|
|
2343
|
+
return name.normalize("NFKD").replace(/[̀-ͯ]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || fallback;
|
|
2344
|
+
}
|
|
2345
|
+
function prettify(slug) {
|
|
2346
|
+
const spaced = slug.replace(/[-_]+/g, " ").trim();
|
|
2347
|
+
return spaced.charAt(0).toUpperCase() + spaced.slice(1);
|
|
2348
|
+
}
|
|
2349
|
+
|
|
2350
|
+
// src/lib/markdown/block-names.ts
|
|
2351
|
+
var BLOCK_OPEN = /^layout_(chapter|spread|page|section|component)_open$/;
|
|
2352
|
+
var BLOCK_CLOSE = /^layout_(chapter|spread|page|section|component)_close$/;
|
|
2353
|
+
var FOLDED = {
|
|
2354
|
+
ß: "ss",
|
|
2355
|
+
æ: "ae",
|
|
2356
|
+
œ: "oe",
|
|
2357
|
+
ø: "o",
|
|
2358
|
+
đ: "d",
|
|
2359
|
+
ð: "d",
|
|
2360
|
+
þ: "th",
|
|
2361
|
+
ł: "l",
|
|
2362
|
+
ı: "i"
|
|
2363
|
+
};
|
|
2364
|
+
function nameSlug(text) {
|
|
2365
|
+
return slugify(text.replace(/['’]/g, "").replace(/[ßæœøđðþłı]/gi, (c) => FOLDED[c.toLowerCase()] ?? c));
|
|
2366
|
+
}
|
|
2367
|
+
function nameFromSrc(src) {
|
|
2368
|
+
if (/^data:/i.test(src))
|
|
2369
|
+
return "";
|
|
2370
|
+
const path = src.split(/[?#]/, 1)[0] ?? "";
|
|
2371
|
+
const base = path.split(/[\\/]/).pop() ?? "";
|
|
2372
|
+
let decoded = base;
|
|
2373
|
+
try {
|
|
2374
|
+
decoded = decodeURIComponent(base);
|
|
2375
|
+
} catch {}
|
|
2376
|
+
return nameSlug(decoded.replace(/\.[^.]*$/, ""));
|
|
2377
|
+
}
|
|
2378
|
+
function takeExplicitName(token) {
|
|
2379
|
+
const data = token.attrGet("data-name");
|
|
2380
|
+
const plain = token.attrGet("name");
|
|
2381
|
+
if (plain !== null && token.attrs)
|
|
2382
|
+
token.attrs = token.attrs.filter(([k]) => k !== "name");
|
|
2383
|
+
if (data)
|
|
2384
|
+
return data;
|
|
2385
|
+
if (plain) {
|
|
2386
|
+
token.attrSet("data-name", plain);
|
|
2387
|
+
return plain;
|
|
2388
|
+
}
|
|
2389
|
+
return "";
|
|
2390
|
+
}
|
|
2391
|
+
function inlineText2(inline) {
|
|
2392
|
+
if (!inline || inline.type !== "inline")
|
|
2393
|
+
return "";
|
|
2394
|
+
const parts = [];
|
|
2395
|
+
for (const child of inline.children ?? []) {
|
|
2396
|
+
if (child.type === "text" || child.type === "text_special" || child.type === "code_inline" || child.type === "image") {
|
|
2397
|
+
parts.push(child.content);
|
|
2398
|
+
} else if (child.type === "softbreak" || child.type === "hardbreak") {
|
|
2399
|
+
parts.push(" ");
|
|
2400
|
+
}
|
|
2401
|
+
}
|
|
2402
|
+
return parts.join("");
|
|
2403
|
+
}
|
|
2404
|
+
function claim(used, slug) {
|
|
2405
|
+
let name = slug;
|
|
2406
|
+
for (let n = 2;used.has(name); n++)
|
|
2407
|
+
name = `${slug}-${n}`;
|
|
2408
|
+
used.add(name);
|
|
2409
|
+
return name;
|
|
2410
|
+
}
|
|
2411
|
+
function nameBlocksAndHeadings(tokens) {
|
|
2412
|
+
const blocks = [];
|
|
2413
|
+
const open = [];
|
|
2414
|
+
const headings = [];
|
|
2415
|
+
const headingSlugs = new Map;
|
|
2416
|
+
for (let i = 0;i < tokens.length; i++) {
|
|
2417
|
+
const tok = tokens[i];
|
|
2418
|
+
const opened = BLOCK_OPEN.exec(tok.type);
|
|
2419
|
+
if (opened) {
|
|
2420
|
+
const block = { token: tok, type: opened[1], heading: "" };
|
|
2421
|
+
blocks.push(block);
|
|
2422
|
+
open.push(block);
|
|
2423
|
+
continue;
|
|
2424
|
+
}
|
|
2425
|
+
const closed = BLOCK_CLOSE.exec(tok.type);
|
|
2426
|
+
if (closed) {
|
|
2427
|
+
for (let j = open.length - 1;j >= 0; j--) {
|
|
2428
|
+
if (open[j].type === closed[1]) {
|
|
2429
|
+
open.splice(j, 1);
|
|
2430
|
+
break;
|
|
2431
|
+
}
|
|
2432
|
+
}
|
|
2433
|
+
continue;
|
|
2434
|
+
}
|
|
2435
|
+
if (tok.type === "heading_open") {
|
|
2436
|
+
const slug = nameSlug(inlineText2(tokens[i + 1]));
|
|
2437
|
+
headings.push(tok);
|
|
2438
|
+
headingSlugs.set(tok, slug);
|
|
2439
|
+
const owner = open[open.length - 1];
|
|
2440
|
+
if (owner && !owner.heading)
|
|
2441
|
+
owner.heading = slug;
|
|
2442
|
+
}
|
|
2443
|
+
}
|
|
2444
|
+
const usedBlocks = new Set;
|
|
2445
|
+
const usedHeadings = new Set;
|
|
2446
|
+
const unnamedBlocks = new Set;
|
|
2447
|
+
for (const block of blocks) {
|
|
2448
|
+
const explicit = block.token.attrGet("data-name");
|
|
2449
|
+
if (explicit)
|
|
2450
|
+
usedBlocks.add(explicit);
|
|
2451
|
+
else
|
|
2452
|
+
unnamedBlocks.add(block);
|
|
2453
|
+
}
|
|
2454
|
+
const unnamedHeadings = [];
|
|
2455
|
+
for (const heading of headings) {
|
|
2456
|
+
const explicit = takeExplicitName(heading);
|
|
2457
|
+
if (explicit)
|
|
2458
|
+
usedHeadings.add(explicit);
|
|
2459
|
+
else
|
|
2460
|
+
unnamedHeadings.push(heading);
|
|
2461
|
+
}
|
|
2462
|
+
let previousSection = null;
|
|
2463
|
+
for (const block of blocks) {
|
|
2464
|
+
const { token } = block;
|
|
2465
|
+
if (block.type === "section") {
|
|
2466
|
+
if (token.meta?.continued && previousSection) {
|
|
2467
|
+
const inherited = previousSection.token.attrGet("data-name");
|
|
2468
|
+
if (inherited)
|
|
2469
|
+
token.attrSet("data-name", inherited);
|
|
2470
|
+
previousSection = block;
|
|
2471
|
+
continue;
|
|
2472
|
+
}
|
|
2473
|
+
previousSection = block;
|
|
2474
|
+
}
|
|
2475
|
+
if (!unnamedBlocks.has(block))
|
|
2476
|
+
continue;
|
|
2477
|
+
const slug = nameSlug(token.attrGet("data-label") ?? "") || block.heading;
|
|
2478
|
+
if (slug)
|
|
2479
|
+
token.attrSet("data-name", claim(usedBlocks, slug));
|
|
2480
|
+
}
|
|
2481
|
+
for (const heading of unnamedHeadings) {
|
|
2482
|
+
const slug = headingSlugs.get(heading);
|
|
2483
|
+
if (slug)
|
|
2484
|
+
heading.attrSet("data-name", claim(usedHeadings, slug));
|
|
2485
|
+
}
|
|
2486
|
+
}
|
|
2487
|
+
function gpBlockNames(md) {
|
|
2488
|
+
md.core.ruler.push("gp_block_names", (state) => nameBlocksAndHeadings(state.tokens));
|
|
2489
|
+
}
|
|
2490
|
+
|
|
2324
2491
|
// src/lib/markdown/renderer.ts
|
|
2325
2492
|
import markdownItSourceMap from "markdown-it-source-map";
|
|
2326
2493
|
import markdownItDeflist from "markdown-it-deflist";
|
|
@@ -2487,6 +2654,10 @@ function registerImageRule(md) {
|
|
|
2487
2654
|
if (srcIdx >= 0 && token.attrs) {
|
|
2488
2655
|
const src = token.attrs[srcIdx][1];
|
|
2489
2656
|
if (src) {
|
|
2657
|
+
const explicit = takeExplicitName(token);
|
|
2658
|
+
const named = explicit || nameFromSrc(src);
|
|
2659
|
+
if (named)
|
|
2660
|
+
token.attrSet("data-name", named);
|
|
2490
2661
|
const bucket = env ?? {};
|
|
2491
2662
|
(bucket.imageRefs ??= []).push(src);
|
|
2492
2663
|
const cls = token.attrGet("class");
|
|
@@ -2862,6 +3033,8 @@ function createMarkdownRenderer(customPlugins) {
|
|
|
2862
3033
|
const declaredMarkers = buildDeclaredMarkerRegistry(declaredMarkerSources);
|
|
2863
3034
|
md.use(plugin, { declaredMarkers });
|
|
2864
3035
|
md.use(gpPinScope);
|
|
3036
|
+
md.use(gpBlockNames);
|
|
3037
|
+
md.use(gpTableAlign);
|
|
2865
3038
|
registerImageRule(md);
|
|
2866
3039
|
if (customPlugins && customPlugins.length > 0) {
|
|
2867
3040
|
applyPlugins(md, customPlugins);
|
|
@@ -2960,6 +3133,8 @@ ${GUTTERPRESS_CSS.trim()}
|
|
|
2960
3133
|
}`,
|
|
2961
3134
|
pluginCss ? `/* extension css */
|
|
2962
3135
|
${pluginCss.trim()}` : null,
|
|
3136
|
+
`/* column alignment */
|
|
3137
|
+
${TABLE_ALIGN_CSS.trim()}`,
|
|
2963
3138
|
projectCss ? `/* project css */
|
|
2964
3139
|
${projectCss.trim()}` : null
|
|
2965
3140
|
].filter(Boolean).join(`
|
|
@@ -4712,15 +4887,6 @@ async function rollbackNpmPluginInstall(installed) {
|
|
|
4712
4887
|
// src/lib/extension-manager.ts
|
|
4713
4888
|
import { gt as semverGt, rcompare as semverRcompare } from "semver";
|
|
4714
4889
|
|
|
4715
|
-
// src/lib/slug.ts
|
|
4716
|
-
function slugify(name, fallback = "") {
|
|
4717
|
-
return name.normalize("NFKD").replace(/[̀-ͯ]/g, "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || fallback;
|
|
4718
|
-
}
|
|
4719
|
-
function prettify(slug) {
|
|
4720
|
-
const spaced = slug.replace(/[-_]+/g, " ").trim();
|
|
4721
|
-
return spaced.charAt(0).toUpperCase() + spaced.slice(1);
|
|
4722
|
-
}
|
|
4723
|
-
|
|
4724
4890
|
// src/lib/project-gitignore.ts
|
|
4725
4891
|
import { readFile as readFile7, writeFile as writeFile2 } from "node:fs/promises";
|
|
4726
4892
|
import path6 from "node:path";
|
|
@@ -5750,7 +5916,7 @@ import git from "isomorphic-git";
|
|
|
5750
5916
|
// package.json
|
|
5751
5917
|
var package_default = {
|
|
5752
5918
|
name: "gutterpress",
|
|
5753
|
-
version: "0.11.18-alpha.
|
|
5919
|
+
version: "0.11.18-alpha.4",
|
|
5754
5920
|
description: "Markdown-to-PDF converter for professional print layout using a native Chromium print engine and Ghostscript.",
|
|
5755
5921
|
author: "itlackey",
|
|
5756
5922
|
license: "MPL-2.0",
|
|
@@ -7620,6 +7786,7 @@ var ruleRemoteUrls = "printsafe/no-remote-urls";
|
|
|
7620
7786
|
var ruleRiskyProps = "printsafe/no-risky-print-effects";
|
|
7621
7787
|
var ruleSyntax = "printsafe/syntax-error";
|
|
7622
7788
|
var rulePageContainment = "printsafe/page-containment";
|
|
7789
|
+
var rulePreviewCannotFollow = "printsafe/preview-cannot-follow";
|
|
7623
7790
|
function extractUrls(value) {
|
|
7624
7791
|
const urls = [];
|
|
7625
7792
|
const re = /url\(\s*(['"]?)(.*?)\1\s*\)/gi;
|
|
@@ -7765,6 +7932,62 @@ function clipsDescendants(decl) {
|
|
|
7765
7932
|
const v = decl.value.trim().toLowerCase();
|
|
7766
7933
|
return v !== "" && !isInertValue(p, v);
|
|
7767
7934
|
}
|
|
7935
|
+
var PREVIEW_AT_RULES = new Set(["media", "supports", "layer", "scope", "container", "document"]);
|
|
7936
|
+
var FORCED_BREAK_VALUE = /^(page|left|right|recto|verso)$/i;
|
|
7937
|
+
var LEGACY_FORCED_VALUE = /^(always|left|right)$/i;
|
|
7938
|
+
function previewBlindSpot(decl) {
|
|
7939
|
+
const prop = decl.prop.toLowerCase();
|
|
7940
|
+
const value = decl.value.trim();
|
|
7941
|
+
const written = `${decl.prop}: ${decl.value}`;
|
|
7942
|
+
const isBreak = prop === "break-before" || prop === "break-after";
|
|
7943
|
+
const isLegacy = prop === "page-break-before" || prop === "page-break-after";
|
|
7944
|
+
if (!isBreak && !isLegacy && prop !== "page")
|
|
7945
|
+
return null;
|
|
7946
|
+
const rules = [];
|
|
7947
|
+
for (let p = decl.parent;p; p = p.parent) {
|
|
7948
|
+
if (p.type === "rule")
|
|
7949
|
+
rules.push(p);
|
|
7950
|
+
else if (p.type === "atrule") {
|
|
7951
|
+
const name = p.name.toLowerCase();
|
|
7952
|
+
if (!PREVIEW_AT_RULES.has(name))
|
|
7953
|
+
return null;
|
|
7954
|
+
}
|
|
7955
|
+
}
|
|
7956
|
+
if (rules.length === 0)
|
|
7957
|
+
return null;
|
|
7958
|
+
const consequence = "the PDF honours it but the live preview does not show it, so the two page counts drift apart";
|
|
7959
|
+
if (isLegacy) {
|
|
7960
|
+
if (!LEGACY_FORCED_VALUE.test(value))
|
|
7961
|
+
return null;
|
|
7962
|
+
const modern = prop.replace("page-break-", "break-");
|
|
7963
|
+
const siblings = decl.parent.nodes ?? [];
|
|
7964
|
+
if (siblings.some((n) => n.type === "decl" && n.prop.toLowerCase() === modern))
|
|
7965
|
+
return null;
|
|
7966
|
+
const keyword = /^always$/i.test(value) ? "page" : value.toLowerCase();
|
|
7967
|
+
return `"${written}" is the legacy spelling, and the live preview reads only ${modern}: ${consequence}. Write "${modern}: ${keyword}".`;
|
|
7968
|
+
}
|
|
7969
|
+
const viaVar = /\bvar\(/i.test(value);
|
|
7970
|
+
if (isBreak && !viaVar && !FORCED_BREAK_VALUE.test(value))
|
|
7971
|
+
return null;
|
|
7972
|
+
if (prop === "page" && !viaVar && (value === "" || /^auto$/i.test(value)))
|
|
7973
|
+
return null;
|
|
7974
|
+
const what = prop === "page" ? "page assignment" : "forced break";
|
|
7975
|
+
if (viaVar) {
|
|
7976
|
+
return `The ${what} "${written}" uses var(): the live preview reads it only as a literal ${prop === "page" ? "page name" : "keyword (page, left, right, recto or verso)"}, so ${consequence}. Write the literal value.`;
|
|
7977
|
+
}
|
|
7978
|
+
const parent = decl.parent;
|
|
7979
|
+
if (rules.length >= 2 || parent.type === "atrule") {
|
|
7980
|
+
const outer = rules[rules.length - 1].selector;
|
|
7981
|
+
return `The ${what} "${written}" is inside a nested rule in "${outer}": the live preview reads only top-level rules and rules inside @media, @supports, @layer, @scope, @container and @document, so ${consequence}. Move it to a flat rule of its own.`;
|
|
7982
|
+
}
|
|
7983
|
+
let prev = decl.prev();
|
|
7984
|
+
while (prev && prev.type === "comment")
|
|
7985
|
+
prev = prev.prev();
|
|
7986
|
+
if (prev && (prev.type === "rule" || prev.type === "atrule" && prev.nodes)) {
|
|
7987
|
+
return `The ${what} "${written}" comes right after a nested rule in "${rules[0].selector}": the live preview's CSS reader drops the first declaration after a nested block, so ${consequence}. Move the declaration above the nested rule.`;
|
|
7988
|
+
}
|
|
7989
|
+
return null;
|
|
7990
|
+
}
|
|
7768
7991
|
function nodeLoc(node) {
|
|
7769
7992
|
return {
|
|
7770
7993
|
line: node.source?.start?.line ?? 1,
|
|
@@ -7877,6 +8100,12 @@ function checkCssRaw(css, from) {
|
|
|
7877
8100
|
});
|
|
7878
8101
|
}
|
|
7879
8102
|
});
|
|
8103
|
+
root.walkDecls((decl) => {
|
|
8104
|
+
const message = previewBlindSpot(decl);
|
|
8105
|
+
if (message) {
|
|
8106
|
+
warnings.push({ rule: rulePreviewCannotFollow, severity: "warning", message, ...nodeLoc(decl) });
|
|
8107
|
+
}
|
|
8108
|
+
});
|
|
7880
8109
|
root.walkRules((rule) => {
|
|
7881
8110
|
if (rule.parent?.type === "atrule") {
|
|
7882
8111
|
const at = rule.parent.name.toLowerCase();
|
|
@@ -8688,10 +8917,117 @@ registerCheck(check25);
|
|
|
8688
8917
|
|
|
8689
8918
|
// src/checks/source/layout-markers.ts
|
|
8690
8919
|
import { readFile as readFile22 } from "node:fs/promises";
|
|
8920
|
+
|
|
8921
|
+
// src/lib/unknown-classes.ts
|
|
8922
|
+
import postcss4 from "postcss";
|
|
8923
|
+
var EMITTED = new Set([
|
|
8924
|
+
"chapter",
|
|
8925
|
+
"spread",
|
|
8926
|
+
"page",
|
|
8927
|
+
"section",
|
|
8928
|
+
"footnotes",
|
|
8929
|
+
"footnotes-sep",
|
|
8930
|
+
"footnote-ref",
|
|
8931
|
+
"footnote-item",
|
|
8932
|
+
"footnote-backref"
|
|
8933
|
+
]);
|
|
8934
|
+
function classesInTokens(tokens) {
|
|
8935
|
+
const uses = new Map;
|
|
8936
|
+
const note = (token, line) => {
|
|
8937
|
+
const cls = token.attrs?.find(([key]) => key === "class")?.[1];
|
|
8938
|
+
if (!cls)
|
|
8939
|
+
return;
|
|
8940
|
+
for (const c of cls.split(/\s+/)) {
|
|
8941
|
+
if (!c || c.startsWith("gp-") || EMITTED.has(c) || /^chapter-\d+$/.test(c))
|
|
8942
|
+
continue;
|
|
8943
|
+
const seen = uses.get(c);
|
|
8944
|
+
if (seen)
|
|
8945
|
+
seen.count++;
|
|
8946
|
+
else
|
|
8947
|
+
uses.set(c, { line, count: 1 });
|
|
8948
|
+
}
|
|
8949
|
+
};
|
|
8950
|
+
for (const token of tokens) {
|
|
8951
|
+
const meta = token.meta;
|
|
8952
|
+
const line = token.map ? token.map[0] + 1 : typeof meta?.line === "number" ? meta.line : 0;
|
|
8953
|
+
note(token, line);
|
|
8954
|
+
for (const child of token.children ?? [])
|
|
8955
|
+
note(child, line);
|
|
8956
|
+
}
|
|
8957
|
+
return uses;
|
|
8958
|
+
}
|
|
8959
|
+
var CLASS_RE = /\.((?:[\w --]|\\.)+)/g;
|
|
8960
|
+
function addSelectorClasses(selector, into) {
|
|
8961
|
+
const bare = selector.replace(/\[(?:[^\]"']|"[^"]*"|'[^']*')*\]/g, "").replace(/"[^"]*"|'[^']*'/g, "");
|
|
8962
|
+
for (const m of bare.matchAll(CLASS_RE)) {
|
|
8963
|
+
const name = m[1].replace(/\\(.)/g, "$1");
|
|
8964
|
+
if (!/^\d/.test(name))
|
|
8965
|
+
into.add(name);
|
|
8966
|
+
}
|
|
8967
|
+
}
|
|
8968
|
+
function addCssClasses(css, into) {
|
|
8969
|
+
try {
|
|
8970
|
+
postcss4.parse(css).walk((node) => {
|
|
8971
|
+
if (node.type === "rule")
|
|
8972
|
+
addSelectorClasses(node.selector, into);
|
|
8973
|
+
else if (node.type === "atrule") {
|
|
8974
|
+
const at = node;
|
|
8975
|
+
if (/^(scope|container)$/i.test(at.name))
|
|
8976
|
+
addSelectorClasses(at.params, into);
|
|
8977
|
+
}
|
|
8978
|
+
});
|
|
8979
|
+
} catch {
|
|
8980
|
+
addSelectorClasses(css.replace(/\/\*[\s\S]*?\*\//g, ""), into);
|
|
8981
|
+
}
|
|
8982
|
+
}
|
|
8983
|
+
function editDistance3(a, b) {
|
|
8984
|
+
let prev = Array.from({ length: b.length + 1 }, (_, j) => j);
|
|
8985
|
+
for (let i = 1;i <= a.length; i++) {
|
|
8986
|
+
const cur = [i];
|
|
8987
|
+
for (let j = 1;j <= b.length; j++) {
|
|
8988
|
+
cur[j] = Math.min(prev[j] + 1, cur[j - 1] + 1, prev[j - 1] + (a[i - 1] === b[j - 1] ? 0 : 1));
|
|
8989
|
+
}
|
|
8990
|
+
prev = cur;
|
|
8991
|
+
}
|
|
8992
|
+
return prev[b.length];
|
|
8993
|
+
}
|
|
8994
|
+
function nearestKnownClass(cls, known) {
|
|
8995
|
+
const limit = cls.length >= 6 ? 2 : 1;
|
|
8996
|
+
let best = null;
|
|
8997
|
+
let bestDistance = limit + 1;
|
|
8998
|
+
for (const candidate of known) {
|
|
8999
|
+
if (Math.abs(candidate.length - cls.length) > limit)
|
|
9000
|
+
continue;
|
|
9001
|
+
const d = editDistance3(cls, candidate);
|
|
9002
|
+
if (d > 0 && d < bestDistance) {
|
|
9003
|
+
best = candidate;
|
|
9004
|
+
bestDistance = d;
|
|
9005
|
+
}
|
|
9006
|
+
}
|
|
9007
|
+
return best;
|
|
9008
|
+
}
|
|
9009
|
+
|
|
9010
|
+
// src/checks/source/layout-markers.ts
|
|
9011
|
+
async function collectKnownClasses(ctx, plugins) {
|
|
9012
|
+
const names = new Set;
|
|
9013
|
+
addCssClasses(MARKER_CSS, names);
|
|
9014
|
+
addCssClasses(GUTTERPRESS_CSS, names);
|
|
9015
|
+
for (const p of plugins)
|
|
9016
|
+
if (p.css)
|
|
9017
|
+
addCssClasses(p.css, names);
|
|
9018
|
+
const roots = [...ctx.cssFiles ?? [], ...plugins.flatMap((p) => p.styles ?? [])];
|
|
9019
|
+
const sheets = (await collectStyleDependencies(ctx.inputDir, roots)).filter((f) => /\.css$/i.test(f));
|
|
9020
|
+
for (const sheet of sheets) {
|
|
9021
|
+
try {
|
|
9022
|
+
addCssClasses(await readFile22(sheet, "utf8"), names);
|
|
9023
|
+
} catch {}
|
|
9024
|
+
}
|
|
9025
|
+
return names;
|
|
9026
|
+
}
|
|
8691
9027
|
var check26 = {
|
|
8692
9028
|
id: "source.markdown.layout-markers",
|
|
8693
9029
|
name: "Layout Markers",
|
|
8694
|
-
description: "Reports @page/@section/@chapter marker arguments Gutterpress could not understand, plus any unknown gp-* class",
|
|
9030
|
+
description: "Reports @page/@section/@chapter marker arguments Gutterpress could not understand, plus any unknown gp-* class and any other class no stylesheet mentions",
|
|
8695
9031
|
category: "source",
|
|
8696
9032
|
phase: "pre-build",
|
|
8697
9033
|
async run(ctx) {
|
|
@@ -8703,11 +9039,31 @@ var check26 = {
|
|
|
8703
9039
|
results.push(inspectionFailed(check26.id, `Plugin "${ref}" could not be loaded, so markers it defines were not checked: ${error2.message}`));
|
|
8704
9040
|
});
|
|
8705
9041
|
const md = createMarkdownRenderer(plugins);
|
|
9042
|
+
let known;
|
|
9043
|
+
const knownClasses = () => known ??= collectKnownClasses(ctx, plugins);
|
|
8706
9044
|
for (const file of files) {
|
|
8707
9045
|
try {
|
|
8708
9046
|
const content = await readFile22(file, "utf8");
|
|
8709
9047
|
const env = {};
|
|
8710
|
-
md.
|
|
9048
|
+
const tokens = md.parse(content, env);
|
|
9049
|
+
md.renderer.render(tokens, md.options, env);
|
|
9050
|
+
const uses = classesInTokens(tokens);
|
|
9051
|
+
if (uses.size > 0) {
|
|
9052
|
+
const names = await knownClasses();
|
|
9053
|
+
const warnedLines = new Set((env.layoutWarnings ?? []).map((w) => w.line));
|
|
9054
|
+
for (const [cls, use] of uses) {
|
|
9055
|
+
if (names.has(cls) || warnedLines.has(use.line))
|
|
9056
|
+
continue;
|
|
9057
|
+
const guess = nearestKnownClass(cls, names);
|
|
9058
|
+
results.push(finding(check26.id, {
|
|
9059
|
+
severity: "warning",
|
|
9060
|
+
message: `Class ".${cls}" is not in any stylesheet (Gutterpress's own, the plugins', or this book's), so it styles nothing.` + (guess ? ` Did you mean ".${guess}"?` : "") + (use.count > 1 ? ` Used ${use.count} times in this file; the first is reported.` : ""),
|
|
9061
|
+
file,
|
|
9062
|
+
...use.line > 0 ? { line: use.line } : {},
|
|
9063
|
+
code: "unknown_class"
|
|
9064
|
+
}));
|
|
9065
|
+
}
|
|
9066
|
+
}
|
|
8711
9067
|
for (const w of env.layoutWarnings ?? []) {
|
|
8712
9068
|
results.push(finding(check26.id, {
|
|
8713
9069
|
severity: w.severity ?? "warning",
|
|
@@ -10306,7 +10662,7 @@ class PdfOutput {
|
|
|
10306
10662
|
const rawPdf = pdfxMode ? path13.join(stage, "raw.pdf") : path13.resolve(pdfFile);
|
|
10307
10663
|
await fsp2.mkdir(path13.dirname(path13.resolve(pdfFile)), { recursive: true });
|
|
10308
10664
|
log.info("Rendering HTML to PDF via the Gutterpress engine (native Chromium pagination)");
|
|
10309
|
-
const { buildNativePdf } = await import("./engine-
|
|
10665
|
+
const { buildNativePdf } = await import("./engine-zw8626be.js");
|
|
10310
10666
|
const engineDiagnostics = await buildNativePdf(htmlFile, rawPdf, {
|
|
10311
10667
|
title: config.title,
|
|
10312
10668
|
author: config.authors.length > 0 ? config.authors.join(", ") : undefined,
|
|
@@ -11782,7 +12138,7 @@ import path20 from "node:path";
|
|
|
11782
12138
|
import { existsSync as existsSync13 } from "node:fs";
|
|
11783
12139
|
import { mkdir as mkdir8, readFile as readFile29, writeFile as writeFile8 } from "node:fs/promises";
|
|
11784
12140
|
import path19 from "node:path";
|
|
11785
|
-
import
|
|
12141
|
+
import postcss5 from "postcss";
|
|
11786
12142
|
import { Scalar as Scalar2 } from "yaml";
|
|
11787
12143
|
function isPositivePoints(value) {
|
|
11788
12144
|
return typeof value === "number" && Number.isFinite(value) && value > 0;
|
|
@@ -11843,7 +12199,7 @@ function sizeDeclsOf(rule) {
|
|
|
11843
12199
|
function readPageSizeFromCss(css) {
|
|
11844
12200
|
let root;
|
|
11845
12201
|
try {
|
|
11846
|
-
root =
|
|
12202
|
+
root = postcss5.parse(css);
|
|
11847
12203
|
} catch {
|
|
11848
12204
|
return null;
|
|
11849
12205
|
}
|
|
@@ -11852,7 +12208,7 @@ function readPageSizeFromCss(css) {
|
|
|
11852
12208
|
return last ? parseSize(last.value) ?? null : null;
|
|
11853
12209
|
}
|
|
11854
12210
|
function setPageSizeInCss(css, page) {
|
|
11855
|
-
const root =
|
|
12211
|
+
const root = postcss5.parse(css);
|
|
11856
12212
|
const decls = plainPageRules(root).flatMap(sizeDeclsOf);
|
|
11857
12213
|
const last = decls[decls.length - 1];
|
|
11858
12214
|
const value = formatPageSize(page);
|
|
@@ -148,7 +148,7 @@ import { fileURLToPath } from "node:url";
|
|
|
148
148
|
var favicon_default = "./favicon-272ga6y0.ico";
|
|
149
149
|
|
|
150
150
|
// src/assets/manifest.schema.json
|
|
151
|
-
var manifest_schema_default = "./manifest.schema-
|
|
151
|
+
var manifest_schema_default = "./manifest.schema-5pzhscqh.json";
|
|
152
152
|
|
|
153
153
|
// src/assets/preview/scripts/preview-interface.js
|
|
154
154
|
var preview_interface_default = "./preview-interface-2n1d9pbf.js";
|
|
@@ -163,7 +163,7 @@ var preview_shell_default = "./preview-shell-hyp7g158.js";
|
|
|
163
163
|
var CGATS21_CRPC1_default = "./CGATS21_CRPC1-g0e3k7kr.icc";
|
|
164
164
|
|
|
165
165
|
// src/assets/engine/gutterpress-viewer.js
|
|
166
|
-
var gutterpress_viewer_default = "./gutterpress-viewer-
|
|
166
|
+
var gutterpress_viewer_default = "./gutterpress-viewer-k4mpqjh0.js";
|
|
167
167
|
|
|
168
168
|
// src/assets/engine/gutterpress-agent.js
|
|
169
169
|
var gutterpress_agent_default = "./gutterpress-agent-cazqstr1.js";
|
package/dist/index.js
CHANGED
|
@@ -153,14 +153,14 @@ import {
|
|
|
153
153
|
testRemoteAccess,
|
|
154
154
|
updateExtensions,
|
|
155
155
|
validateProjectExtensions
|
|
156
|
-
} from "./index-
|
|
156
|
+
} from "./index-1ergtg60.js";
|
|
157
157
|
import"./index-ht1bcqdd.js";
|
|
158
158
|
import {
|
|
159
159
|
BUILD_DIAGNOSTIC_CODES
|
|
160
|
-
} from "./index-
|
|
160
|
+
} from "./index-qbd874dh.js";
|
|
161
161
|
import {
|
|
162
162
|
BuildError
|
|
163
|
-
} from "./index-
|
|
163
|
+
} from "./index-jt552wtf.js";
|
|
164
164
|
import {
|
|
165
165
|
DEFAULT_PRINT_OPTS,
|
|
166
166
|
assertMilestone,
|