gutterpress 0.11.23-alpha.3 → 0.11.23-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/README.md +4 -6
- package/dist/{README-8db7btxb.md → README-syg2hn83.md} +1 -1
- package/dist/api/index.js +5 -5
- package/dist/{build-m78jcpf7.js → build-c48eer6f.js} +8 -8
- package/dist/checks/asset/extensions.d.ts +1 -1
- package/dist/checks/asset/index.d.ts +0 -1
- package/dist/checks/policy.d.ts +5 -4
- package/dist/checks/source/config-file.d.ts +9 -6
- package/dist/checks/source/dangling-links.d.ts +1 -1
- package/dist/checks/types.d.ts +2 -2
- package/dist/{cli-xsrffqzt.js → cli-54xt7pjg.js} +8 -8
- package/dist/{cli-2ppw6q9v.js → cli-5crpmz42.js} +80 -1
- package/dist/{cli-1h17ktsg.js → cli-93mkaw6v.js} +96 -209
- package/dist/{cli-n2tsxqpn.js → cli-d9mm3vvh.js} +7 -2
- package/dist/{cli-5jzyw06s.js → cli-gnpea9dx.js} +1 -1
- package/dist/{cli-s6djx4ma.js → cli-pspjxnc8.js} +1 -1
- package/dist/{cli-t8be9yeb.js → cli-rqh295j9.js} +12 -7
- package/dist/{cli-h4x81x97.js → cli-y6d1arem.js} +207 -142
- package/dist/cli.js +12 -12
- package/dist/{doctor-j71jqce3.js → doctor-ptb346k8.js} +4 -3
- package/dist/{engine-m4y10shc.js → engine-4rzdx6af.js} +1 -1
- package/dist/{engine-1r6q80tq.js → engine-6txhxmmv.js} +2 -2
- package/dist/{ext-fq2hg9va.js → ext-gy8szg3x.js} +8 -8
- package/dist/{extension-restore-9dh7c4tp.js → extension-restore-dymzcasz.js} +2 -2
- package/dist/{extension-restore-tmxtzkm0.js → extension-restore-m8tj43e7.js} +4 -4
- package/dist/{index-2ppw6q9v.js → index-5crpmz42.js} +80 -1
- package/dist/{index-nedd07bk.js → index-5kh4c78h.js} +8 -8
- package/dist/{index-0wee4408.js → index-8ywkd2sv.js} +12 -7
- package/dist/{index-prqvz3xm.js → index-ea94zbq4.js} +132 -228
- package/dist/{index-7pck1q9c.js → index-kaks3mm2.js} +206 -141
- package/dist/{index-nvmf22rt.js → index-yc3xj266.js} +1 -1
- package/dist/index.js +6 -6
- package/dist/lib/build-preflight.d.ts +4 -10
- package/dist/lib/build-runner.d.ts +1 -1
- package/dist/lib/ghostscript.d.ts +5 -2
- package/dist/lib/lint-rules.d.ts +5 -1
- package/dist/lib/manifest-config.d.ts +3 -2
- package/dist/lib/manifest-old-spellings.d.ts +64 -0
- package/dist/lib/markdown/chapter-id.d.ts +1 -1
- package/dist/lib/markdown/index.d.ts +1 -1
- package/dist/lib/markdown/table.d.ts +5 -3
- package/dist/lib/page-size.d.ts +14 -9
- package/dist/lib/pdf-inspect.d.ts +27 -0
- package/dist/lib/presets.d.ts +10 -8
- package/dist/lib/printsafe.d.ts +1 -1
- package/dist/lib/project-scaffold.d.ts +1 -1
- package/dist/lib/remote-auth/sync-messages.d.ts +2 -2
- package/dist/lib/targets.d.ts +4 -4
- package/dist/lib/validation-exec.d.ts +4 -4
- package/dist/{manifest-my7mdv8j.yaml → manifest-2kc56wvw.yaml} +3 -4
- package/dist/{manifest-8afhrk30.yaml → manifest-41ddzm13.yaml} +3 -4
- package/dist/{manifest-gf13sjp8.yaml → manifest-79zsgkpn.yaml} +3 -4
- package/dist/{manifest-d4f9q79e.yaml → manifest-sqzm4681.yaml} +3 -4
- package/dist/{manifest.schema-650pe0d1.json → manifest.schema-w86c1xw1.json} +19 -309
- package/dist/{new-s4zcaepg.js → new-t2t28ccb.js} +9 -15
- package/dist/{page-rules-fj09xct5.css → page-rules-ytj9p04v.css} +1 -1
- package/dist/{pdf-inspect-wnw4za71.js → pdf-inspect-b3mf81ex.js} +3 -1
- package/dist/{plugins-80emnf31.js → plugins-fec8t2bh.js} +1 -1
- package/dist/{plugins-4vaf27n9.js → plugins-sqa4msdk.js} +3 -3
- package/dist/{preflight-c7w1xdn3.js → preflight-srq8fktp.js} +8 -8
- package/dist/preview/file-watcher.d.ts +1 -3
- package/dist/{preview-mzytcwyk.js → preview-zsp9hstd.js} +8 -8
- package/dist/{publish-fez14ad4.js → publish-hhy31gr9.js} +8 -8
- package/dist/render.js +6 -1
- package/dist/schema/manifest.types.d.ts +40 -107
- package/dist/{tokens-ye64p899.css → tokens-n82t4k9h.css} +11 -4
- package/dist/{validate-p2chr6hr.js → validate-r9jdz85h.js} +8 -8
- package/package.json +1 -1
- package/dist/checks/asset/approved-fonts.d.ts +0 -3
|
@@ -37,7 +37,7 @@ import {
|
|
|
37
37
|
validatePageMargin,
|
|
38
38
|
withFetchTimeout,
|
|
39
39
|
writeManifestDoc
|
|
40
|
-
} from "./index-
|
|
40
|
+
} from "./index-kaks3mm2.js";
|
|
41
41
|
import {
|
|
42
42
|
EXTENSION_MANIFEST_FILENAME,
|
|
43
43
|
GUTTERPRESS_CSS,
|
|
@@ -73,7 +73,7 @@ import {
|
|
|
73
73
|
setLogLevel,
|
|
74
74
|
slugify,
|
|
75
75
|
warn
|
|
76
|
-
} from "./index-
|
|
76
|
+
} from "./index-8ywkd2sv.js";
|
|
77
77
|
import {
|
|
78
78
|
blackTextToGray
|
|
79
79
|
} from "./index-ht1bcqdd.js";
|
|
@@ -84,7 +84,7 @@ import {
|
|
|
84
84
|
getAssetPath,
|
|
85
85
|
lastPageMode,
|
|
86
86
|
resolvePage
|
|
87
|
-
} from "./index-
|
|
87
|
+
} from "./index-5kh4c78h.js";
|
|
88
88
|
import {
|
|
89
89
|
BuildError
|
|
90
90
|
} from "./index-46ycxe6r.js";
|
|
@@ -99,8 +99,9 @@ import {
|
|
|
99
99
|
isLoadable,
|
|
100
100
|
loadPdf,
|
|
101
101
|
pageHasMarks,
|
|
102
|
+
pagesWithVisibleShadingPaints,
|
|
102
103
|
retainPdfCache
|
|
103
|
-
} from "./index-
|
|
104
|
+
} from "./index-5crpmz42.js";
|
|
104
105
|
import {
|
|
105
106
|
INSTALL_HINTS,
|
|
106
107
|
enhancedPath,
|
|
@@ -156,14 +157,14 @@ var MSG_UP_TO_DATE = "Everything is in sync.";
|
|
|
156
157
|
var MSG_UP_TO_DATE_PULLED = "Everything is in sync. The latest online changes were downloaded to this computer.";
|
|
157
158
|
var MSG_SYNCED = "Your changes are online.";
|
|
158
159
|
var MSG_SYNCED_MERGED = "Your changes are online, combined with changes from the online copy.";
|
|
159
|
-
var MSG_OFFLINE = "Your changes are saved on this computer.
|
|
160
|
+
var MSG_OFFLINE = "Your changes are saved on this computer. Gutterpress couldn't reach the online repository — try syncing again when you're back online.";
|
|
160
161
|
var MSG_AUTH = "The online repository didn't accept the saved connection. Reconnect and try again.";
|
|
161
162
|
var MSG_INSECURE_TRANSPORT = "This book's online address isn't secure, so the saved connection wasn't sent — connections are never sent over an insecure address. Switch the address to a secure one (starting with https), or to a local loopback address for a server on this computer, to sync.";
|
|
162
163
|
var MSG_BUSY = "The online copy is changing very quickly right now. Your work is saved on this computer — try Sync again in a moment.";
|
|
163
164
|
var MSG_HISTORY_UNREADABLE = "This book's version history can't be read, so syncing can't continue. Your writing is safe — every file is still here on this computer. Use Repair online backup (in Where your work is kept) to get history and syncing working again.";
|
|
164
165
|
var MSG_UNRELATED = "This book and the online copy have no history in common, so they can't be combined. Either the online address points at a different book, or this book's own history was lost and started over. Your writing is safe — every file is still here on this computer. Check the online address; if it is correct, use Repair online backup (in Where your work is kept).";
|
|
165
166
|
var MSG_NO_REMOTE = "This book isn't connected to an online repository yet.";
|
|
166
|
-
var MSG_SSH_REMOTE = "This book's online address uses SSH (git@…), which
|
|
167
|
+
var MSG_SSH_REMOTE = "This book's online address uses SSH (git@…), which Gutterpress can't sync to. Switch it to the web (HTTPS) address to sync from here.";
|
|
167
168
|
var MSG_NO_BRANCH = "This book's version history isn't on a named branch, so it can't be synced right now.";
|
|
168
169
|
var SYNC_SNAPSHOT_MESSAGE = "Automatic backup of your work";
|
|
169
170
|
var SYNC_LATE_EDIT_MESSAGE = "Saved the edit you made while syncing";
|
|
@@ -955,7 +956,9 @@ async function findPostScriptShadingPages(pdfBytes) {
|
|
|
955
956
|
if (usesPostScriptShading(asDict(page.node.Resources())))
|
|
956
957
|
pages.push(i + 1);
|
|
957
958
|
});
|
|
958
|
-
|
|
959
|
+
if (pages.length === 0)
|
|
960
|
+
return pages;
|
|
961
|
+
return pagesWithVisibleShadingPaints(pdfBytes, pages).catch(() => pages);
|
|
959
962
|
}
|
|
960
963
|
async function stripAnnotations(pdfPath, stagingDir) {
|
|
961
964
|
const tmp = join2(stagingDir, "annotations-stripped.pdf");
|
|
@@ -1350,7 +1353,7 @@ async function writeBuildFingerprint(input) {
|
|
|
1350
1353
|
// src/lib/validation-exec.ts
|
|
1351
1354
|
import { existsSync as existsSync7 } from "node:fs";
|
|
1352
1355
|
import { readFile as readFile20 } from "node:fs/promises";
|
|
1353
|
-
import { dirname as
|
|
1356
|
+
import { dirname as dirname3, join as join3, resolve as resolve5 } from "node:path";
|
|
1354
1357
|
|
|
1355
1358
|
// src/lib/markdownlint-fix.ts
|
|
1356
1359
|
import { readFile as readFile6, writeFile as writeFile4 } from "node:fs/promises";
|
|
@@ -1359,18 +1362,20 @@ import { lint as lint2 } from "markdownlint/sync";
|
|
|
1359
1362
|
|
|
1360
1363
|
// src/checks/source/config-file.ts
|
|
1361
1364
|
import { existsSync as existsSync3 } from "node:fs";
|
|
1362
|
-
import { resolve as resolve2 } from "node:path";
|
|
1363
|
-
function findConfigFile(
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1365
|
+
import { dirname, resolve as resolve2 } from "node:path";
|
|
1366
|
+
function findConfigFile(startDir, names) {
|
|
1367
|
+
let dir = resolve2(startDir);
|
|
1368
|
+
for (;; ) {
|
|
1369
|
+
for (const name of names) {
|
|
1370
|
+
const p = resolve2(dir, name);
|
|
1371
|
+
if (existsSync3(p))
|
|
1372
|
+
return p;
|
|
1373
|
+
}
|
|
1374
|
+
const parent = dirname(dir);
|
|
1375
|
+
if (existsSync3(resolve2(dir, ".git")) || parent === dir)
|
|
1376
|
+
return null;
|
|
1377
|
+
dir = parent;
|
|
1372
1378
|
}
|
|
1373
|
-
return null;
|
|
1374
1379
|
}
|
|
1375
1380
|
|
|
1376
1381
|
// src/checks/source/markdownlint.ts
|
|
@@ -1482,17 +1487,13 @@ var check = {
|
|
|
1482
1487
|
category: "source",
|
|
1483
1488
|
phase: "pre-build",
|
|
1484
1489
|
async run(ctx) {
|
|
1485
|
-
const sourceConfig = ctx.config.validate.source;
|
|
1486
|
-
if (sourceConfig.markdownlint === false)
|
|
1487
|
-
return [];
|
|
1488
1490
|
const files = ctx.markdownFiles;
|
|
1489
1491
|
if (!files || files.length === 0)
|
|
1490
1492
|
return [];
|
|
1491
|
-
const
|
|
1492
|
-
|
|
1493
|
-
if (!resolvedConfig && !configPath)
|
|
1493
|
+
const resolvedConfig = findConfigFile(ctx.inputDir, CONFIG_NAMES);
|
|
1494
|
+
if (!resolvedConfig)
|
|
1494
1495
|
return [];
|
|
1495
|
-
const config =
|
|
1496
|
+
const config = await loadConfig(resolvedConfig);
|
|
1496
1497
|
const results = lint({ files, config });
|
|
1497
1498
|
const out = [];
|
|
1498
1499
|
for (const [file, violations] of Object.entries(results)) {
|
|
@@ -1531,8 +1532,7 @@ async function uncommittedAmong(inputDir, files) {
|
|
|
1531
1532
|
return files.filter((file) => changed.has(repoSubPath(repoRoot, file)));
|
|
1532
1533
|
}
|
|
1533
1534
|
async function applyMarkdownlintFixes(ctx) {
|
|
1534
|
-
|
|
1535
|
-
if (sourceConfig.markdownlint === false) {
|
|
1535
|
+
if (ctx.config.checks["source.markdownlint"] === "off") {
|
|
1536
1536
|
log.warn("--fix: source.markdownlint is disabled for this book — no files were fixed.");
|
|
1537
1537
|
return [];
|
|
1538
1538
|
}
|
|
@@ -1541,13 +1541,12 @@ async function applyMarkdownlintFixes(ctx) {
|
|
|
1541
1541
|
log.warn("--fix: no markdown files to fix.");
|
|
1542
1542
|
return [];
|
|
1543
1543
|
}
|
|
1544
|
-
const
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
log.warn(`--fix: no markdownlint config found in ${ctx.inputDir} (looked for ${CONFIG_NAMES.join(", ")}) — no files were fixed.`);
|
|
1544
|
+
const resolvedConfig = findConfigFile(ctx.inputDir, CONFIG_NAMES);
|
|
1545
|
+
if (!resolvedConfig) {
|
|
1546
|
+
log.warn(`--fix: no markdownlint config found in ${ctx.inputDir} or a folder above it (looked for ${CONFIG_NAMES.join(", ")}) — no files were fixed.`);
|
|
1548
1547
|
return [];
|
|
1549
1548
|
}
|
|
1550
|
-
const config =
|
|
1549
|
+
const config = await loadConfig(resolvedConfig);
|
|
1551
1550
|
const results = lint2({ files, config });
|
|
1552
1551
|
const pending = [];
|
|
1553
1552
|
for (const [file, violations] of Object.entries(results)) {
|
|
@@ -1581,10 +1580,7 @@ import { readFile as readFile7 } from "node:fs/promises";
|
|
|
1581
1580
|
// src/checks/policy.ts
|
|
1582
1581
|
var INSPECT_FAILED_CODE = "inspect-failed";
|
|
1583
1582
|
function isCheckEnabled(check2, config) {
|
|
1584
|
-
|
|
1585
|
-
if (entry === false)
|
|
1586
|
-
return false;
|
|
1587
|
-
if (typeof entry === "object" && entry.enabled === false)
|
|
1583
|
+
if (config.checks[check2.id] === "off")
|
|
1588
1584
|
return false;
|
|
1589
1585
|
if (check2.enabledWhen && !check2.enabledWhen(config))
|
|
1590
1586
|
return false;
|
|
@@ -2327,7 +2323,7 @@ var check9 = {
|
|
|
2327
2323
|
severity: "warning",
|
|
2328
2324
|
message: `Dark four-colour text at ${LARGE_TEXT_PT}pt or smaller on page(s) ${found.pages.join(", ")}.`,
|
|
2329
2325
|
file: ctx.pdfPath,
|
|
2330
|
-
detail: "Small text printed with all four inks can look fuzzy if the plates are slightly out of register, which is why print vendors such as DriveThruRPG want small black text on the black plate alone. `pdfx.blackText: k-only` already does that for near-black text; this text is either a dark colour (for example a dark brown, which keeps its colour) or painted in a way the build cannot rewrite (an image or a pattern). To print it on the black plate, make the text black (#000). If the colour is intended, set `
|
|
2326
|
+
detail: "Small text printed with all four inks can look fuzzy if the plates are slightly out of register, which is why print vendors such as DriveThruRPG want small black text on the black plate alone. `pdfx.blackText: k-only` already does that for near-black text; this text is either a dark colour (for example a dark brown, which keeps its colour) or painted in a way the build cannot rewrite (an image or a pattern). To print it on the black plate, make the text black (#000). If the colour is intended, set `checks: { pdf.print.black-text: off }` in manifest.yaml.",
|
|
2331
2327
|
code: "rich-black-text",
|
|
2332
2328
|
data: { runs: found.runs, pages: found.pages }
|
|
2333
2329
|
})
|
|
@@ -2407,8 +2403,6 @@ var check11 = {
|
|
|
2407
2403
|
async run(ctx) {
|
|
2408
2404
|
if (!ctx.pdfPath)
|
|
2409
2405
|
return [];
|
|
2410
|
-
if (!ctx.config.validate.pdf.requireBookmarks)
|
|
2411
|
-
return [];
|
|
2412
2406
|
const doc = await loadPdf(ctx.pdfPath);
|
|
2413
2407
|
if (!doc) {
|
|
2414
2408
|
return [
|
|
@@ -2441,8 +2435,6 @@ var check12 = {
|
|
|
2441
2435
|
async run(ctx) {
|
|
2442
2436
|
if (!ctx.pdfPath)
|
|
2443
2437
|
return [];
|
|
2444
|
-
if (!ctx.config.validate.pdf.requireTocLinks)
|
|
2445
|
-
return [];
|
|
2446
2438
|
const doc = await loadPdf(ctx.pdfPath);
|
|
2447
2439
|
if (!doc) {
|
|
2448
2440
|
return [
|
|
@@ -2580,8 +2572,6 @@ var check16 = {
|
|
|
2580
2572
|
async run(ctx) {
|
|
2581
2573
|
if (!ctx.pdfPath)
|
|
2582
2574
|
return [];
|
|
2583
|
-
if (!ctx.config.validate.pdf.forbidTransparency)
|
|
2584
|
-
return [];
|
|
2585
2575
|
const bytes = await readPdfBytes(ctx.pdfPath).catch(() => "");
|
|
2586
2576
|
const found = [];
|
|
2587
2577
|
if (bytes.includes("/Transparency"))
|
|
@@ -2622,8 +2612,6 @@ var check17 = {
|
|
|
2622
2612
|
async run(ctx) {
|
|
2623
2613
|
if (!ctx.pdfPath)
|
|
2624
2614
|
return [];
|
|
2625
|
-
if (!ctx.config.validate.pdf.requireBleed)
|
|
2626
|
-
return [];
|
|
2627
2615
|
const bytes = await readPdfBytes(ctx.pdfPath).catch(() => "");
|
|
2628
2616
|
if (!bytes) {
|
|
2629
2617
|
return [
|
|
@@ -2720,14 +2708,10 @@ var check19 = {
|
|
|
2720
2708
|
category: "source",
|
|
2721
2709
|
phase: "pre-build",
|
|
2722
2710
|
async run(ctx) {
|
|
2723
|
-
const sourceConfig = ctx.config.validate.source;
|
|
2724
|
-
if (sourceConfig.htmlhint === false)
|
|
2725
|
-
return [];
|
|
2726
2711
|
if (!ctx.htmlPath || !existsSync4(ctx.htmlPath))
|
|
2727
2712
|
return [];
|
|
2728
|
-
const
|
|
2729
|
-
|
|
2730
|
-
if (!resolvedConfig && !configPath)
|
|
2713
|
+
const resolvedConfig = findConfigFile(ctx.inputDir, CONFIG_NAMES2);
|
|
2714
|
+
if (!resolvedConfig)
|
|
2731
2715
|
return [];
|
|
2732
2716
|
const ruleset = resolvedConfig ? JSON.parse(await readFile10(resolvedConfig, "utf8")) : HTMLHint.defaultRuleset;
|
|
2733
2717
|
const html = await readFile10(ctx.htmlPath, "utf8");
|
|
@@ -2755,7 +2739,7 @@ function ruleLevel(rules, id) {
|
|
|
2755
2739
|
const v = rules?.[id];
|
|
2756
2740
|
if (v === "off" || v === false)
|
|
2757
2741
|
return "off";
|
|
2758
|
-
if (v === "warn" || v === "warning")
|
|
2742
|
+
if (v === "warn" || v === "warning" || v === "info")
|
|
2759
2743
|
return "warn";
|
|
2760
2744
|
if (v === "error")
|
|
2761
2745
|
return "error";
|
|
@@ -3074,7 +3058,7 @@ function checkCssRaw(css, from) {
|
|
|
3074
3058
|
warnings.push({
|
|
3075
3059
|
rule: rulePageSizeInStylesheet,
|
|
3076
3060
|
severity: "warning",
|
|
3077
|
-
message: `"size" in a stylesheet's @page rule is ignored: the page size comes from the manifest (preset:, or page: width and height — Setup >
|
|
3061
|
+
message: `"size" in a stylesheet's @page rule is ignored: the page size comes from the manifest (preset:, or page: width and height — Setup > Book in the app), which is written after every stylesheet. Remove this declaration; to print at another size, change the manifest.`,
|
|
3078
3062
|
...nodeLoc(decl)
|
|
3079
3063
|
});
|
|
3080
3064
|
return;
|
|
@@ -3174,10 +3158,7 @@ var check20 = {
|
|
|
3174
3158
|
description: "Checks CSS for print-safety issues (remote URLs, rasterizing effects, and page-layer containment)",
|
|
3175
3159
|
category: "source",
|
|
3176
3160
|
phase: "pre-build",
|
|
3177
|
-
enabledWhen: (config) => config.validate.source.stylelint !== false,
|
|
3178
3161
|
async run(ctx) {
|
|
3179
|
-
if (ctx.config.validate.source.stylelint === false)
|
|
3180
|
-
return [];
|
|
3181
3162
|
const files = ctx.cssFiles;
|
|
3182
3163
|
if (!files || files.length === 0)
|
|
3183
3164
|
return [];
|
|
@@ -3195,7 +3176,7 @@ var check20 = {
|
|
|
3195
3176
|
});
|
|
3196
3177
|
continue;
|
|
3197
3178
|
}
|
|
3198
|
-
for (const w of checkCss(css, file, { rules: ctx.config.
|
|
3179
|
+
for (const w of checkCss(css, file, { rules: ctx.config.checks })) {
|
|
3199
3180
|
results.push({
|
|
3200
3181
|
checkId: check20.id,
|
|
3201
3182
|
severity: w.severity,
|
|
@@ -3336,15 +3317,11 @@ var check21 = {
|
|
|
3336
3317
|
description: "Checks an optional per-project CSS ownership contract (.gutterpress/css-contract.yaml): which file may declare which properties/at-rules, and which selectors must never appear unscoped.",
|
|
3337
3318
|
category: "source",
|
|
3338
3319
|
phase: "pre-build",
|
|
3339
|
-
enabledWhen: (config) => config.validate.source.cssOwnership !== false,
|
|
3340
3320
|
async run(ctx) {
|
|
3341
|
-
if (ctx.config.validate.source.cssOwnership === false)
|
|
3342
|
-
return [];
|
|
3343
3321
|
const files = ctx.cssFiles;
|
|
3344
3322
|
if (!files || files.length === 0)
|
|
3345
3323
|
return [];
|
|
3346
|
-
const
|
|
3347
|
-
const configPath = findConfigFile(ctx.inputDir, CONFIG_NAMES3, explicit);
|
|
3324
|
+
const configPath = findConfigFile(ctx.inputDir, CONFIG_NAMES3);
|
|
3348
3325
|
if (!configPath)
|
|
3349
3326
|
return [];
|
|
3350
3327
|
let contract;
|
|
@@ -3411,7 +3388,7 @@ registerCheck(check21);
|
|
|
3411
3388
|
|
|
3412
3389
|
// src/checks/source/local-refs.ts
|
|
3413
3390
|
import { existsSync as existsSync5 } from "node:fs";
|
|
3414
|
-
import { dirname, resolve as resolve3 } from "node:path";
|
|
3391
|
+
import { dirname as dirname2, resolve as resolve3 } from "node:path";
|
|
3415
3392
|
var check22 = {
|
|
3416
3393
|
id: "source.links.local-refs",
|
|
3417
3394
|
name: "Local Markdown References",
|
|
@@ -3451,7 +3428,7 @@ function filesystemRef(ref) {
|
|
|
3451
3428
|
}
|
|
3452
3429
|
function localRefExists(ref, kind, sourceFile, projectRoot) {
|
|
3453
3430
|
const cleaned = filesystemRef(ref);
|
|
3454
|
-
const fileRelative = resolve3(
|
|
3431
|
+
const fileRelative = resolve3(dirname2(sourceFile), cleaned);
|
|
3455
3432
|
const rootRelative = resolve3(projectRoot, cleaned);
|
|
3456
3433
|
switch (kind) {
|
|
3457
3434
|
case "image":
|
|
@@ -4527,8 +4504,6 @@ var check30 = {
|
|
|
4527
4504
|
category: "asset",
|
|
4528
4505
|
phase: "pre-build",
|
|
4529
4506
|
async run(ctx) {
|
|
4530
|
-
if (ctx.config.validate.assets.allowAlpha)
|
|
4531
|
-
return [];
|
|
4532
4507
|
if (ctx.config.pdfx.transparency === "preserve-text")
|
|
4533
4508
|
return [];
|
|
4534
4509
|
const files = shippedImages(ctx, ["png", "tiff", "tif"]);
|
|
@@ -4551,58 +4526,6 @@ var check30 = {
|
|
|
4551
4526
|
};
|
|
4552
4527
|
registerCheck(check30);
|
|
4553
4528
|
|
|
4554
|
-
// src/checks/asset/approved-fonts.ts
|
|
4555
|
-
var check31 = {
|
|
4556
|
-
id: "asset.font.approved-files",
|
|
4557
|
-
name: "Approved Font Files",
|
|
4558
|
-
description: "Checks font files against the approved file patterns",
|
|
4559
|
-
category: "asset",
|
|
4560
|
-
phase: "pre-build",
|
|
4561
|
-
async run(ctx) {
|
|
4562
|
-
const patterns = ctx.config.validate.assets.approvedFontFiles;
|
|
4563
|
-
if (!patterns || patterns.length === 0)
|
|
4564
|
-
return [];
|
|
4565
|
-
const { glob } = await import("glob");
|
|
4566
|
-
const dirs = ctx.assetDirs ?? [ctx.inputDir];
|
|
4567
|
-
const allFonts = [];
|
|
4568
|
-
for (const dir of dirs) {
|
|
4569
|
-
const matches = await glob(`**/*.{${FONT_EXTS2.join(",")}}`, {
|
|
4570
|
-
cwd: dir,
|
|
4571
|
-
absolute: true,
|
|
4572
|
-
ignore: [...ASSET_SCAN_IGNORE_GLOBS]
|
|
4573
|
-
});
|
|
4574
|
-
allFonts.push(...matches);
|
|
4575
|
-
}
|
|
4576
|
-
if (allFonts.length === 0)
|
|
4577
|
-
return [];
|
|
4578
|
-
const approvedFonts = new Set;
|
|
4579
|
-
for (const dir of dirs) {
|
|
4580
|
-
for (const pattern of patterns) {
|
|
4581
|
-
const matches = await glob(pattern, {
|
|
4582
|
-
cwd: dir,
|
|
4583
|
-
absolute: true,
|
|
4584
|
-
ignore: [...ASSET_SCAN_IGNORE_GLOBS]
|
|
4585
|
-
});
|
|
4586
|
-
for (const m of matches)
|
|
4587
|
-
approvedFonts.add(m);
|
|
4588
|
-
}
|
|
4589
|
-
}
|
|
4590
|
-
const results = [];
|
|
4591
|
-
for (const font of allFonts) {
|
|
4592
|
-
if (!approvedFonts.has(font)) {
|
|
4593
|
-
results.push({
|
|
4594
|
-
checkId: check31.id,
|
|
4595
|
-
severity: "warning",
|
|
4596
|
-
message: "Font file not in approved list",
|
|
4597
|
-
file: font
|
|
4598
|
-
});
|
|
4599
|
-
}
|
|
4600
|
-
}
|
|
4601
|
-
return results;
|
|
4602
|
-
}
|
|
4603
|
-
};
|
|
4604
|
-
registerCheck(check31);
|
|
4605
|
-
|
|
4606
4529
|
// src/checks/asset/font-license.ts
|
|
4607
4530
|
import { existsSync as existsSync6 } from "node:fs";
|
|
4608
4531
|
import { resolve as resolve4 } from "node:path";
|
|
@@ -4616,15 +4539,13 @@ var LICENSE_NAMES = [
|
|
|
4616
4539
|
"OFL-1.1.txt",
|
|
4617
4540
|
"COPYING"
|
|
4618
4541
|
];
|
|
4619
|
-
var
|
|
4542
|
+
var check31 = {
|
|
4620
4543
|
id: "asset.font.license",
|
|
4621
4544
|
name: "Font License",
|
|
4622
4545
|
description: "Checks for license files in font directories",
|
|
4623
4546
|
category: "asset",
|
|
4624
4547
|
phase: "pre-build",
|
|
4625
4548
|
async run(ctx) {
|
|
4626
|
-
if (!ctx.config.validate.assets.requireFontLicense)
|
|
4627
|
-
return [];
|
|
4628
4549
|
const { glob } = await import("glob");
|
|
4629
4550
|
const dirs = ctx.assetDirs ?? [ctx.inputDir];
|
|
4630
4551
|
const fontDirs = new Set;
|
|
@@ -4643,7 +4564,7 @@ var check32 = {
|
|
|
4643
4564
|
const hasLicense = LICENSE_NAMES.some((name) => existsSync6(resolve4(fontDir, name)));
|
|
4644
4565
|
if (!hasLicense) {
|
|
4645
4566
|
results.push({
|
|
4646
|
-
checkId:
|
|
4567
|
+
checkId: check31.id,
|
|
4647
4568
|
severity: "warning",
|
|
4648
4569
|
message: `No font license file found in directory`,
|
|
4649
4570
|
file: fontDir
|
|
@@ -4653,10 +4574,10 @@ var check32 = {
|
|
|
4653
4574
|
return results;
|
|
4654
4575
|
}
|
|
4655
4576
|
};
|
|
4656
|
-
registerCheck(
|
|
4577
|
+
registerCheck(check31);
|
|
4657
4578
|
|
|
4658
4579
|
// src/checks/heuristic/text-density.ts
|
|
4659
|
-
var
|
|
4580
|
+
var check32 = {
|
|
4660
4581
|
id: "heuristic.whitespace.text-density",
|
|
4661
4582
|
name: "Text Density",
|
|
4662
4583
|
description: "Checks characters-per-page ratio",
|
|
@@ -4685,7 +4606,7 @@ var check33 = {
|
|
|
4685
4606
|
});
|
|
4686
4607
|
if (lowPages.length > 0) {
|
|
4687
4608
|
results.push({
|
|
4688
|
-
checkId:
|
|
4609
|
+
checkId: check32.id,
|
|
4689
4610
|
severity: "info",
|
|
4690
4611
|
message: `Low text density on pages: ${lowPages.join(", ")} (below ${range.min} chars)`,
|
|
4691
4612
|
file: ctx.pdfPath
|
|
@@ -4693,7 +4614,7 @@ var check33 = {
|
|
|
4693
4614
|
}
|
|
4694
4615
|
if (highPages.length > 0) {
|
|
4695
4616
|
results.push({
|
|
4696
|
-
checkId:
|
|
4617
|
+
checkId: check32.id,
|
|
4697
4618
|
severity: "info",
|
|
4698
4619
|
message: `High text density on pages: ${highPages.join(", ")} (above ${range.max} chars)`,
|
|
4699
4620
|
file: ctx.pdfPath
|
|
@@ -4702,11 +4623,11 @@ var check33 = {
|
|
|
4702
4623
|
return results;
|
|
4703
4624
|
}
|
|
4704
4625
|
};
|
|
4705
|
-
registerCheck(
|
|
4626
|
+
registerCheck(check32);
|
|
4706
4627
|
|
|
4707
4628
|
// src/checks/heuristic/section-density.ts
|
|
4708
4629
|
import { readFile as readFile19 } from "node:fs/promises";
|
|
4709
|
-
var
|
|
4630
|
+
var check33 = {
|
|
4710
4631
|
id: "heuristic.chunking.section-density",
|
|
4711
4632
|
name: "Section Density",
|
|
4712
4633
|
description: "Checks heading/paragraph/callout density from source Markdown",
|
|
@@ -4732,7 +4653,7 @@ var check34 = {
|
|
|
4732
4653
|
const line = lines[i];
|
|
4733
4654
|
if (/^#{1,6}\s/.test(line)) {
|
|
4734
4655
|
if (paragraphCount > maxParas) {
|
|
4735
|
-
results.push(finding(
|
|
4656
|
+
results.push(finding(check33.id, {
|
|
4736
4657
|
severity: "info",
|
|
4737
4658
|
message: `Section has ${paragraphCount} paragraphs (max recommended: ${maxParas})`,
|
|
4738
4659
|
file,
|
|
@@ -4752,7 +4673,7 @@ var check34 = {
|
|
|
4752
4673
|
}
|
|
4753
4674
|
}
|
|
4754
4675
|
if (paragraphCount > maxParas) {
|
|
4755
|
-
results.push(finding(
|
|
4676
|
+
results.push(finding(check33.id, {
|
|
4756
4677
|
severity: "info",
|
|
4757
4678
|
message: `Section has ${paragraphCount} paragraphs (max recommended: ${maxParas})`,
|
|
4758
4679
|
file,
|
|
@@ -4760,7 +4681,7 @@ var check34 = {
|
|
|
4760
4681
|
}));
|
|
4761
4682
|
}
|
|
4762
4683
|
} catch {
|
|
4763
|
-
results.push(inspectionFailed(
|
|
4684
|
+
results.push(inspectionFailed(check33.id, `Could not read source file: ${file}`, {
|
|
4764
4685
|
file
|
|
4765
4686
|
}));
|
|
4766
4687
|
}
|
|
@@ -4768,10 +4689,10 @@ var check34 = {
|
|
|
4768
4689
|
return results;
|
|
4769
4690
|
}
|
|
4770
4691
|
};
|
|
4771
|
-
registerCheck(
|
|
4692
|
+
registerCheck(check33);
|
|
4772
4693
|
|
|
4773
4694
|
// src/checks/heuristic/layer-count.ts
|
|
4774
|
-
var
|
|
4695
|
+
var check34 = {
|
|
4775
4696
|
id: "heuristic.decoration.layer-count",
|
|
4776
4697
|
name: "Layer Count",
|
|
4777
4698
|
description: "Counts image objects per page",
|
|
@@ -4796,7 +4717,7 @@ var check35 = {
|
|
|
4796
4717
|
heavyPages.sort((a, b) => a - b);
|
|
4797
4718
|
return [
|
|
4798
4719
|
{
|
|
4799
|
-
checkId:
|
|
4720
|
+
checkId: check34.id,
|
|
4800
4721
|
severity: "info",
|
|
4801
4722
|
message: `Pages with many image layers (>${maxLayers}): ${heavyPages.join(", ")}`,
|
|
4802
4723
|
file: ctx.pdfPath
|
|
@@ -4806,10 +4727,10 @@ var check35 = {
|
|
|
4806
4727
|
return [];
|
|
4807
4728
|
}
|
|
4808
4729
|
};
|
|
4809
|
-
registerCheck(
|
|
4730
|
+
registerCheck(check34);
|
|
4810
4731
|
|
|
4811
4732
|
// src/checks/heuristic/placement-variance.ts
|
|
4812
|
-
var
|
|
4733
|
+
var check35 = {
|
|
4813
4734
|
id: "heuristic.layout.placement-variance",
|
|
4814
4735
|
name: "Placement Variance",
|
|
4815
4736
|
description: "Analyzes text baseline coordinates for layout consistency",
|
|
@@ -4827,7 +4748,7 @@ var check36 = {
|
|
|
4827
4748
|
const uniqueX = new Set(positions.map((p) => Math.round(p.x)));
|
|
4828
4749
|
return [
|
|
4829
4750
|
{
|
|
4830
|
-
checkId:
|
|
4751
|
+
checkId: check35.id,
|
|
4831
4752
|
severity: "info",
|
|
4832
4753
|
message: `Layout analysis: ${uniqueX.size} unique horizontal text positions across ${positions.length} text blocks.`,
|
|
4833
4754
|
file: ctx.pdfPath
|
|
@@ -4835,19 +4756,14 @@ var check36 = {
|
|
|
4835
4756
|
];
|
|
4836
4757
|
}
|
|
4837
4758
|
};
|
|
4838
|
-
registerCheck(
|
|
4759
|
+
registerCheck(check35);
|
|
4839
4760
|
|
|
4840
4761
|
// src/checks/runner.ts
|
|
4841
4762
|
function getCheckSeverityOverride(checkId, config) {
|
|
4842
|
-
const
|
|
4843
|
-
|
|
4844
|
-
return entry.severity;
|
|
4845
|
-
return;
|
|
4763
|
+
const level = config.checks[checkId];
|
|
4764
|
+
return level === "off" || level === "on" ? undefined : level;
|
|
4846
4765
|
}
|
|
4847
4766
|
async function runChecks(ctx, opts = {}) {
|
|
4848
|
-
if (ctx.config.validate.enabled === false) {
|
|
4849
|
-
return emptyReport();
|
|
4850
|
-
}
|
|
4851
4767
|
const { checks: selected, unmatched: unmatchedSelectors } = selectChecks(opts, ctx.config);
|
|
4852
4768
|
let checks2 = selected;
|
|
4853
4769
|
if (opts.skipMissingTools && opts.skipMissingTools.length > 0) {
|
|
@@ -4865,32 +4781,25 @@ async function runChecks(ctx, opts = {}) {
|
|
|
4865
4781
|
}
|
|
4866
4782
|
const release = retainPdfCache();
|
|
4867
4783
|
try {
|
|
4868
|
-
for (const
|
|
4784
|
+
for (const check36 of checks2) {
|
|
4869
4785
|
try {
|
|
4870
|
-
|
|
4871
|
-
const severityOverride = getCheckSeverityOverride(
|
|
4786
|
+
const results = await check36.run(ctx);
|
|
4787
|
+
const severityOverride = getCheckSeverityOverride(check36.id, ctx.config);
|
|
4872
4788
|
if (severityOverride) {
|
|
4873
4789
|
for (const r of results) {
|
|
4874
4790
|
r.severity = severityOverride;
|
|
4875
4791
|
}
|
|
4876
4792
|
}
|
|
4877
|
-
const lintLevel = ruleLevel(ctx.config.lint.rules, check37.id);
|
|
4878
|
-
if (lintLevel === "off")
|
|
4879
|
-
results = [];
|
|
4880
|
-
else if (lintLevel) {
|
|
4881
|
-
for (const r of results)
|
|
4882
|
-
r.severity = lintLevel === "warn" ? "warning" : "error";
|
|
4883
|
-
}
|
|
4884
4793
|
if (results.length === 0) {
|
|
4885
|
-
passed.push(
|
|
4794
|
+
passed.push(check36.id);
|
|
4886
4795
|
} else {
|
|
4887
4796
|
allResults.push(...results);
|
|
4888
4797
|
}
|
|
4889
4798
|
} catch (err) {
|
|
4890
4799
|
allResults.push({
|
|
4891
|
-
checkId:
|
|
4800
|
+
checkId: check36.id,
|
|
4892
4801
|
severity: "error",
|
|
4893
|
-
message: `Check "${
|
|
4802
|
+
message: `Check "${check36.id}" threw: ${err instanceof Error ? err.message : String(err)}`
|
|
4894
4803
|
});
|
|
4895
4804
|
}
|
|
4896
4805
|
}
|
|
@@ -4915,30 +4824,20 @@ async function runChecks(ctx, opts = {}) {
|
|
|
4915
4824
|
}
|
|
4916
4825
|
};
|
|
4917
4826
|
}
|
|
4918
|
-
function emptyReport() {
|
|
4919
|
-
return {
|
|
4920
|
-
results: [],
|
|
4921
|
-
errors: [],
|
|
4922
|
-
warnings: [],
|
|
4923
|
-
infos: [],
|
|
4924
|
-
passed: [],
|
|
4925
|
-
summary: { total: 0, errors: 0, warnings: 0, infos: 0, passed: 0 }
|
|
4926
|
-
};
|
|
4927
|
-
}
|
|
4928
4827
|
|
|
4929
4828
|
// src/checks/tool-check.ts
|
|
4930
4829
|
async function checkToolAvailability(config, opts = {}) {
|
|
4931
4830
|
const { checks: checks2 } = selectChecks(opts, config);
|
|
4932
4831
|
const toolToChecks = new Map;
|
|
4933
|
-
for (const
|
|
4934
|
-
if (!
|
|
4832
|
+
for (const check36 of checks2) {
|
|
4833
|
+
if (!check36.requiredTools?.length)
|
|
4935
4834
|
continue;
|
|
4936
|
-
for (const tool of
|
|
4835
|
+
for (const tool of check36.requiredTools) {
|
|
4937
4836
|
const existing = toolToChecks.get(tool);
|
|
4938
4837
|
if (existing) {
|
|
4939
|
-
existing.push(
|
|
4838
|
+
existing.push(check36.id);
|
|
4940
4839
|
} else {
|
|
4941
|
-
toolToChecks.set(tool, [
|
|
4840
|
+
toolToChecks.set(tool, [check36.id]);
|
|
4942
4841
|
}
|
|
4943
4842
|
}
|
|
4944
4843
|
}
|
|
@@ -4954,11 +4853,11 @@ async function checkToolAvailability(config, opts = {}) {
|
|
|
4954
4853
|
const missing = results.filter((r) => !r.found).map((r) => r.tool);
|
|
4955
4854
|
const missingSet = new Set(missing);
|
|
4956
4855
|
const skippedChecks = [];
|
|
4957
|
-
for (const
|
|
4958
|
-
if (!
|
|
4856
|
+
for (const check36 of checks2) {
|
|
4857
|
+
if (!check36.requiredTools?.length)
|
|
4959
4858
|
continue;
|
|
4960
|
-
if (
|
|
4961
|
-
skippedChecks.push(
|
|
4859
|
+
if (check36.requiredTools.some((t) => missingSet.has(t))) {
|
|
4860
|
+
skippedChecks.push(check36.id);
|
|
4962
4861
|
}
|
|
4963
4862
|
}
|
|
4964
4863
|
return { available, missing, skippedChecks, toolToChecks };
|
|
@@ -5029,7 +4928,7 @@ async function sharedAssetDirs(manifestDir, relStyles, inputDir) {
|
|
|
5029
4928
|
const ext = file.slice(file.lastIndexOf(".")).toLowerCase();
|
|
5030
4929
|
if (!SHIPPED_ASSET_EXTS.has(ext))
|
|
5031
4930
|
continue;
|
|
5032
|
-
const dir =
|
|
4931
|
+
const dir = dirname3(resolve5(file));
|
|
5033
4932
|
if (escapesProjectRoot(projectRoot, dir))
|
|
5034
4933
|
dirs.add(dir);
|
|
5035
4934
|
}
|
|
@@ -5190,7 +5089,7 @@ function planRuns(opts) {
|
|
|
5190
5089
|
async function executeValidation(args) {
|
|
5191
5090
|
const manifestPath = typeof args.manifest === "string" ? args.manifest : undefined;
|
|
5192
5091
|
const { manifest, manifestDir } = await loadManifestWithPath(manifestPath ?? args.input ?? undefined, { explicit: manifestPath !== undefined });
|
|
5193
|
-
const config = resolveConfig(args.skipStylelint ? {
|
|
5092
|
+
const config = resolveConfig(args.skipStylelint ? { checks: { "source.stylelint": "off" } } : {}, manifest);
|
|
5194
5093
|
const targetIds = resolveTargets(parseCsv(typeof args.target === "string" ? args.target : undefined), config.targets);
|
|
5195
5094
|
const pdfPath = typeof args.pdf === "string" ? resolve5(args.pdf) : undefined;
|
|
5196
5095
|
const inputDir = typeof args.input === "string" ? resolve5(args.input) : undefined;
|
|
@@ -5223,7 +5122,7 @@ async function executeValidation(args) {
|
|
|
5223
5122
|
let htmlPath;
|
|
5224
5123
|
const outDir = resolveOutputDir(manifestDir, config.title);
|
|
5225
5124
|
if (inputDir) {
|
|
5226
|
-
const relMarkdown = await resolveActiveMarkdownFiles(manifestDir, config.
|
|
5125
|
+
const relMarkdown = await resolveActiveMarkdownFiles(manifestDir, config.chapters);
|
|
5227
5126
|
markdownFiles = relMarkdown.map((f) => join3(manifestDir, canonicalChapterId(f)));
|
|
5228
5127
|
const relStyles = await resolveActiveStyles(manifestDir, config.styles);
|
|
5229
5128
|
const projectCssFiles = relStyles.map((rel) => resolve5(manifestDir, rel));
|
|
@@ -5259,7 +5158,7 @@ async function executeValidation(args) {
|
|
|
5259
5158
|
};
|
|
5260
5159
|
if (args.fix) {
|
|
5261
5160
|
const selected = selectChecks(runnerOptions, config).checks;
|
|
5262
|
-
if (selected.some((
|
|
5161
|
+
if (selected.some((check36) => check36.id === MARKDOWNLINT_CHECK_ID)) {
|
|
5263
5162
|
await applyMarkdownlintFixes(context);
|
|
5264
5163
|
} else {
|
|
5265
5164
|
log.warn(`--fix: ${MARKDOWNLINT_CHECK_ID} is not part of this run — no files were fixed.`);
|
|
@@ -5362,16 +5261,16 @@ ${list}
|
|
|
5362
5261
|
|
|
5363
5262
|
Install the missing tools and re-run, or set GHOSTSCRIPT_PATH, CHROMIUM_PATH, or system PATH so gutterpress can find them. See the User Guide Chapter 7 (System Setup) at examples/gutterpress-user-guide/07-system-setup.md for the full per-feature matrix.`, 2);
|
|
5364
5263
|
}
|
|
5365
|
-
function computeGates(format, opts
|
|
5264
|
+
function computeGates(format, opts) {
|
|
5366
5265
|
if (format === "html") {
|
|
5367
5266
|
if (opts.skipLint || opts.skipPreValidate || opts.skipPostValidate) {
|
|
5368
5267
|
log.info("Validation/lint flags ignored for --format html (no validation phases apply)");
|
|
5369
5268
|
}
|
|
5370
5269
|
return { skipStylelint: false, preValidate: false, postValidate: false };
|
|
5371
5270
|
}
|
|
5372
|
-
const skipStylelint = !!opts.skipLint
|
|
5373
|
-
const preValidate = !opts.skipPreValidate
|
|
5374
|
-
const postValidate = format === "pdfx" && !opts.skipPostValidate
|
|
5271
|
+
const skipStylelint = !!opts.skipLint;
|
|
5272
|
+
const preValidate = !opts.skipPreValidate;
|
|
5273
|
+
const postValidate = format === "pdfx" && !opts.skipPostValidate;
|
|
5375
5274
|
return { skipStylelint, preValidate, postValidate };
|
|
5376
5275
|
}
|
|
5377
5276
|
|
|
@@ -5407,7 +5306,7 @@ async function resolveBuildContext(opts) {
|
|
|
5407
5306
|
}, manifest);
|
|
5408
5307
|
const target = opts.pdfFileOverride ? { kind: "file", file: path7.resolve(opts.pdfFileOverride) } : opts.outDir ? { kind: "directory", dir: opts.outDir } : { kind: "project", dir: resolveOutputDir(manifestDir, config.title) };
|
|
5409
5308
|
const outDir = target.kind === "file" ? path7.dirname(target.file) : target.dir;
|
|
5410
|
-
const gates = computeGates(format, opts
|
|
5309
|
+
const gates = computeGates(format, opts);
|
|
5411
5310
|
const workDir = target.kind === "project" ? path7.join(path7.dirname(target.dir), `.${path7.basename(target.dir)}-build-${randomBytes(6).toString("hex")}`) : path7.join(os2.tmpdir(), `gutterpress-build-${randomBytes(6).toString("hex")}`);
|
|
5412
5311
|
return {
|
|
5413
5312
|
opts,
|
|
@@ -5463,8 +5362,8 @@ async function runQualityGates(ctx) {
|
|
|
5463
5362
|
}
|
|
5464
5363
|
async function renderBook(ctx) {
|
|
5465
5364
|
const { config, gates, renderDir, workDir, opts, format } = ctx;
|
|
5466
|
-
if (config.
|
|
5467
|
-
log.info(`Using specified files (${config.
|
|
5365
|
+
if (config.chapters && config.chapters.length > 0) {
|
|
5366
|
+
log.info(`Using specified files (${config.chapters.length} total)`);
|
|
5468
5367
|
} else {
|
|
5469
5368
|
log.info("Using all .md files in alphabetical order");
|
|
5470
5369
|
}
|
|
@@ -5477,7 +5376,7 @@ async function renderBook(ctx) {
|
|
|
5477
5376
|
print: config.print,
|
|
5478
5377
|
printArea: { ...config.page, preset: config.preset, spec: config.spec },
|
|
5479
5378
|
styles: config.styles,
|
|
5480
|
-
files: config.
|
|
5379
|
+
files: config.chapters,
|
|
5481
5380
|
plugins,
|
|
5482
5381
|
pluginStyles,
|
|
5483
5382
|
onChapterWarnings: (file, warnings) => {
|
|
@@ -5628,7 +5527,7 @@ class PdfOutput {
|
|
|
5628
5527
|
const rawPdf = pdfxMode ? path7.join(stage, "raw.pdf") : path7.resolve(pdfFile);
|
|
5629
5528
|
await fsp2.mkdir(path7.dirname(path7.resolve(pdfFile)), { recursive: true });
|
|
5630
5529
|
log.info("Rendering HTML to PDF via the Gutterpress engine (native Chromium pagination)");
|
|
5631
|
-
const { buildNativePdf } = await import("./engine-
|
|
5530
|
+
const { buildNativePdf } = await import("./engine-6txhxmmv.js");
|
|
5632
5531
|
const engineDiagnostics = await buildNativePdf(htmlFile, rawPdf, {
|
|
5633
5532
|
title: config.title,
|
|
5634
5533
|
author: config.authors.length > 0 ? config.authors.join(", ") : undefined,
|
|
@@ -5665,7 +5564,7 @@ class PdfOutput {
|
|
|
5665
5564
|
}
|
|
5666
5565
|
const flattenPages = config.pdfx.flattenPages;
|
|
5667
5566
|
if (transparent.length > 0 && config.pdfx.transparency === "preserve-text") {
|
|
5668
|
-
const { unsplittableTextReasons } = await import("./pdf-inspect-
|
|
5567
|
+
const { unsplittableTextReasons } = await import("./pdf-inspect-b3mf81ex.js");
|
|
5669
5568
|
const reasons = await unsplittableTextReasons(rawBytes, transparent).catch((err) => {
|
|
5670
5569
|
log.warn(`pdfx.transparency: preserve-text could not inspect this PDF's text (${err instanceof Error ? err.message : String(err)}), so every page that uses transparency is flattened whole, as with flatten-page.`);
|
|
5671
5570
|
return null;
|
|
@@ -5938,7 +5837,7 @@ async function generateAndWriteHtml(inputPath, tempDir, config, cssAssets, image
|
|
|
5938
5837
|
...config,
|
|
5939
5838
|
printArea: config.page && { ...config.page, preset: config.preset, spec: config.spec }
|
|
5940
5839
|
}, {
|
|
5941
|
-
files: config.
|
|
5840
|
+
files: config.chapters ?? null,
|
|
5942
5841
|
onCssAssets: (copies) => {
|
|
5943
5842
|
for (const copy of copies)
|
|
5944
5843
|
nextAssets.set(copy.to, copy.from);
|
|
@@ -7175,12 +7074,10 @@ import { readFile as readFile24 } from "node:fs/promises";
|
|
|
7175
7074
|
import path13 from "node:path";
|
|
7176
7075
|
import { isMap } from "yaml";
|
|
7177
7076
|
function writePageBounds(doc, page) {
|
|
7178
|
-
const tolerance = page.tolerance ?? numberAt(doc, ["page", "tolerance"]);
|
|
7179
7077
|
ensurePageMap(doc);
|
|
7180
7078
|
doc.setIn(["page", "width"], page.width);
|
|
7181
7079
|
doc.setIn(["page", "height"], page.height);
|
|
7182
|
-
|
|
7183
|
-
doc.setIn(["page", "tolerance"], tolerance);
|
|
7080
|
+
doc.deleteIn(["page", "tolerance"]);
|
|
7184
7081
|
}
|
|
7185
7082
|
function deletePageBounds(doc) {
|
|
7186
7083
|
const block = doc.get("page", true);
|
|
@@ -7193,6 +7090,14 @@ function deletePageBounds(doc) {
|
|
|
7193
7090
|
if (block.items.length === 0)
|
|
7194
7091
|
doc.delete("page");
|
|
7195
7092
|
}
|
|
7093
|
+
function deletePageMargin(doc) {
|
|
7094
|
+
const block = doc.get("page", true);
|
|
7095
|
+
if (!isMap(block))
|
|
7096
|
+
return;
|
|
7097
|
+
block.delete("margin");
|
|
7098
|
+
if (block.items.length === 0)
|
|
7099
|
+
doc.delete("page");
|
|
7100
|
+
}
|
|
7196
7101
|
function writePageMargin(doc, margin) {
|
|
7197
7102
|
ensurePageMap(doc);
|
|
7198
7103
|
if (!isMap(doc.getIn(["page", "margin"], true)))
|
|
@@ -7228,11 +7133,12 @@ function manifestGeometry(doc) {
|
|
|
7228
7133
|
const base = preset ? PRESETS[preset].page : null;
|
|
7229
7134
|
const width = numberAt(doc, ["page", "width"]) ?? base?.width;
|
|
7230
7135
|
const height = numberAt(doc, ["page", "height"]) ?? base?.height;
|
|
7231
|
-
const tolerance =
|
|
7136
|
+
const tolerance = base?.tolerance ?? 0.5;
|
|
7232
7137
|
const bounds = width !== undefined && height !== undefined ? { width, height, tolerance } : null;
|
|
7138
|
+
const presetSizeOverridden = base !== null && (numberAt(doc, ["page", "width"]) !== undefined || numberAt(doc, ["page", "height"]) !== undefined);
|
|
7233
7139
|
const at = (edge) => doc.getIn(["page", "margin", edge]);
|
|
7234
7140
|
const margins = MARGIN_EDGES.every((edge) => isNonNegativePoints(at(edge))) ? { top: at("top"), bottom: at("bottom"), inside: at("inside"), outside: at("outside") } : undefined;
|
|
7235
|
-
return { preset, bounds, ...margins ? { margins } : {} };
|
|
7141
|
+
return { preset, bounds, presetSizeOverridden, ...margins ? { margins } : {} };
|
|
7236
7142
|
}
|
|
7237
7143
|
async function stylesheetMargins(projectDir, manifestStyles) {
|
|
7238
7144
|
const d = DEFAULT_PAGE_MARGIN_PT;
|
|
@@ -7267,10 +7173,9 @@ async function stylesheetMargins(projectDir, manifestStyles) {
|
|
|
7267
7173
|
}
|
|
7268
7174
|
async function setupOf(projectDir, doc) {
|
|
7269
7175
|
const { margins, ...geometry } = manifestGeometry(doc);
|
|
7270
|
-
if (margins)
|
|
7271
|
-
return { ...geometry, margins, marginsFrom: "manifest" };
|
|
7272
7176
|
const styles = doc.toJS()?.styles;
|
|
7273
|
-
|
|
7177
|
+
const sheets = await stylesheetMargins(projectDir, Array.isArray(styles) ? styles : undefined);
|
|
7178
|
+
return margins ? { ...geometry, margins, marginsFrom: "manifest", fallbackMarginsFrom: sheets.marginsFrom } : { ...geometry, ...sheets, fallbackMarginsFrom: sheets.marginsFrom };
|
|
7274
7179
|
}
|
|
7275
7180
|
async function readPageSetup(projectDir) {
|
|
7276
7181
|
const { doc } = await loadManifestDoc(projectDir);
|
|
@@ -7280,7 +7185,7 @@ async function setPageSetup(projectDir, change) {
|
|
|
7280
7185
|
const { doc, file } = await loadManifestDoc(projectDir);
|
|
7281
7186
|
const size2 = change.size ? pageSizeForChoice(change.size) : null;
|
|
7282
7187
|
let margins;
|
|
7283
|
-
if (change.margins
|
|
7188
|
+
if (change.margins) {
|
|
7284
7189
|
const against = size2 ?? manifestGeometry(doc).bounds;
|
|
7285
7190
|
if (!against)
|
|
7286
7191
|
throw new UsageError("Choose a page size before setting margins: the manifest records none.");
|
|
@@ -7295,6 +7200,8 @@ async function setPageSetup(projectDir, change) {
|
|
|
7295
7200
|
}
|
|
7296
7201
|
if (margins)
|
|
7297
7202
|
writePageMargin(doc, margins);
|
|
7203
|
+
else if (change.margins === null)
|
|
7204
|
+
deletePageMargin(doc);
|
|
7298
7205
|
await writeManifestDoc(file, doc);
|
|
7299
7206
|
return setupOf(projectDir, doc);
|
|
7300
7207
|
}
|
|
@@ -7304,10 +7211,10 @@ function starterOverridesCss() {
|
|
|
7304
7211
|
return `/**
|
|
7305
7212
|
* Your book's own styles. Rules here win over your look's.
|
|
7306
7213
|
*
|
|
7307
|
-
* In the app you rarely need this file: Setup >
|
|
7308
|
-
*
|
|
7309
|
-
*
|
|
7310
|
-
* page size and margins (in the manifest).
|
|
7214
|
+
* In the app you rarely need this file: Setup > Look chooses a look and
|
|
7215
|
+
* changes its fonts and colors (those changes are saved here as :root
|
|
7216
|
+
* custom properties), Setup > Advanced lists every setting, and Setup > Book
|
|
7217
|
+
* sets the page size and margins (in the manifest).
|
|
7311
7218
|
*
|
|
7312
7219
|
* To change the look from the command line: gutterpress ext remove <old>
|
|
7313
7220
|
* <book>, then gutterpress ext add <look> <book>.
|
|
@@ -7346,9 +7253,6 @@ function requirePreset(preset, customPage) {
|
|
|
7346
7253
|
} else if (customPage && (!isPositivePoints(customPage.width) || !isPositivePoints(customPage.height))) {
|
|
7347
7254
|
throw new CreateProjectErrorImpl("custom-page-required", "Page overrides need a positive width and height in points (72pt = 1in).");
|
|
7348
7255
|
}
|
|
7349
|
-
if (customPage?.tolerance !== undefined && !isPositivePoints(customPage.tolerance)) {
|
|
7350
|
-
throw new CreateProjectErrorImpl("custom-page-required", "Page tolerance must be a positive number of points.");
|
|
7351
|
-
}
|
|
7352
7256
|
return preset;
|
|
7353
7257
|
}
|
|
7354
7258
|
function resolveScaffoldTargets(requested, preset) {
|
|
@@ -7517,7 +7421,7 @@ async function adoptFolder(options) {
|
|
|
7517
7421
|
if (!existsSync9(bookCssPath)) {
|
|
7518
7422
|
await writeFile7(bookCssPath, starterOverridesCss(), "utf8");
|
|
7519
7423
|
}
|
|
7520
|
-
const filesYaml = mdFiles.map((f) => `
|
|
7424
|
+
const filesYaml = mdFiles.map((f) => ` - "${escapeYamlScalar(f)}"`).join(`
|
|
7521
7425
|
`);
|
|
7522
7426
|
const manifest = `title: "${escapeYamlScalar(title)}"
|
|
7523
7427
|
authors:
|
|
@@ -7525,8 +7429,7 @@ authors:
|
|
|
7525
7429
|
preset: dtrpg
|
|
7526
7430
|
targets:
|
|
7527
7431
|
- dtrpg
|
|
7528
|
-
|
|
7529
|
-
files:
|
|
7432
|
+
chapters:
|
|
7530
7433
|
${filesYaml}
|
|
7531
7434
|
styles:
|
|
7532
7435
|
- styles/book.css
|
|
@@ -7574,7 +7477,7 @@ async function firstSourceFile(manifestPath) {
|
|
|
7574
7477
|
} catch {
|
|
7575
7478
|
return;
|
|
7576
7479
|
}
|
|
7577
|
-
const filesIdx = text.search(
|
|
7480
|
+
const filesIdx = text.search(/^(?:chapters|\s+files):\s*$/m);
|
|
7578
7481
|
if (filesIdx === -1)
|
|
7579
7482
|
return;
|
|
7580
7483
|
const rest = text.slice(filesIdx);
|
|
@@ -8654,15 +8557,16 @@ async function setManifestFields(projectDir, updates) {
|
|
|
8654
8557
|
}
|
|
8655
8558
|
if (hasKey(updates, "sourceFiles")) {
|
|
8656
8559
|
const f = updates.sourceFiles;
|
|
8657
|
-
|
|
8658
|
-
|
|
8659
|
-
|
|
8660
|
-
if (
|
|
8560
|
+
const source = doc.get("source", true);
|
|
8561
|
+
if (isMap3(source)) {
|
|
8562
|
+
source.delete("files");
|
|
8563
|
+
if (source.items.length === 0)
|
|
8661
8564
|
doc.delete("source");
|
|
8662
|
-
}
|
|
8663
|
-
} else {
|
|
8664
|
-
doc.setIn(["source", "files"], f);
|
|
8665
8565
|
}
|
|
8566
|
+
if (f === null || Array.isArray(f) && f.length === 0)
|
|
8567
|
+
doc.delete("chapters");
|
|
8568
|
+
else
|
|
8569
|
+
doc.set("chapters", f);
|
|
8666
8570
|
}
|
|
8667
8571
|
await writeManifestDoc(file, doc);
|
|
8668
8572
|
return readManifestFields(projectDir);
|
|
@@ -8682,13 +8586,13 @@ async function readManifestFields(projectDir) {
|
|
|
8682
8586
|
if (isSeq2(targetsNode)) {
|
|
8683
8587
|
out.targets = targetsNode.items.map((i) => scalarString(i)).filter((s) => s !== null);
|
|
8684
8588
|
}
|
|
8685
|
-
const
|
|
8589
|
+
const sourceNode = doc.get("source", true);
|
|
8590
|
+
const oldSpelling = isMap3(sourceNode) && sourceNode.has("files");
|
|
8591
|
+
const filesNode = doc.has("chapters") ? doc.get("chapters", true) : doc.getIn(["source", "files"], true);
|
|
8686
8592
|
if (isSeq2(filesNode)) {
|
|
8687
8593
|
out.sourceFiles = filesNode.items.map((i) => scalarString(i) ?? "");
|
|
8688
|
-
} else {
|
|
8689
|
-
|
|
8690
|
-
if (isMap3(sourceNode) && sourceNode.has("files"))
|
|
8691
|
-
out.sourceFiles = null;
|
|
8594
|
+
} else if (doc.has("chapters") || oldSpelling) {
|
|
8595
|
+
out.sourceFiles = null;
|
|
8692
8596
|
}
|
|
8693
8597
|
return out;
|
|
8694
8598
|
} catch {
|
|
@@ -10839,7 +10743,7 @@ var FAILURE_MESSAGES = {
|
|
|
10839
10743
|
auth: "The Git server didn't accept the saved connection. Reconnect to this server with a current access token and try again.",
|
|
10840
10744
|
"not-found": "The server answered, but no repository was found at that address. It may have been moved, renamed, or you may no longer have access.",
|
|
10841
10745
|
unreachable: "Couldn't reach the Git server. Check your internet connection (and VPN, if this is a private server), then try again.",
|
|
10842
|
-
"ssh-unsupported": "This book's online address uses SSH (git@…), which
|
|
10746
|
+
"ssh-unsupported": "This book's online address uses SSH (git@…), which Gutterpress can't check or sync with. Everything on this computer still works — sync with your usual Git tool.",
|
|
10843
10747
|
"insecure-transport": "This address isn't secure, so the saved connection wasn't sent — connections are never sent over an insecure address. Switch the address to a secure one (starting with https), or to a local loopback address for a server on this computer, to use a saved connection.",
|
|
10844
10748
|
tls: "The server's security certificate couldn't be verified. If this is a private server with its own certificate, ask its administrator about trusting it (NODE_EXTRA_CA_CERTS).",
|
|
10845
10749
|
unknown: "The connection test failed unexpectedly. The server may not be a Git server, or it may be temporarily unavailable."
|
|
@@ -12569,7 +12473,7 @@ async function resolvePublishProvider(id, book) {
|
|
|
12569
12473
|
const ext = await bookExtensions(book);
|
|
12570
12474
|
const npmEntry = ext.extensions.some((c) => !c.path && c.name === id);
|
|
12571
12475
|
if (npmEntry) {
|
|
12572
|
-
const { restoreForCommand: restoreForCommand2 } = await import("./extension-restore-
|
|
12476
|
+
const { restoreForCommand: restoreForCommand2 } = await import("./extension-restore-dymzcasz.js");
|
|
12573
12477
|
await restoreForCommand2(book.projectDir, { manifestPath: book.manifestPath, failFast: true });
|
|
12574
12478
|
}
|
|
12575
12479
|
const publishers = await discover(ext);
|
|
@@ -12607,7 +12511,7 @@ function infoFor(p) {
|
|
|
12607
12511
|
}
|
|
12608
12512
|
function pluginProvider(p) {
|
|
12609
12513
|
let loading;
|
|
12610
|
-
const load = () => loading ??= import("./plugins-
|
|
12514
|
+
const load = () => loading ??= import("./plugins-fec8t2bh.js").then((m) => m.loadPublishFunction(p));
|
|
12611
12515
|
return {
|
|
12612
12516
|
info: infoFor(p),
|
|
12613
12517
|
async authenticate() {
|