gutterpress 0.11.23-alpha.2 → 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 +10 -13
- package/dist/{README-8ef336pp.md → README-syg2hn83.md} +13 -19
- package/dist/api/index.d.ts +1 -1
- package/dist/api/index.js +5 -5
- package/dist/{build-encgnv0c.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-pz4bn98t.js → cli-54xt7pjg.js} +19 -13
- package/dist/{index-2ppw6q9v.js → cli-5crpmz42.js} +80 -1
- package/dist/{cli-xq6djqbj.js → cli-93mkaw6v.js} +166 -308
- package/dist/{cli-evg8sbht.js → cli-d9mm3vvh.js} +7 -2
- package/dist/{cli-kh8v4vvw.js → cli-gnpea9dx.js} +1 -1
- package/dist/{cli-aqh6brew.js → cli-pspjxnc8.js} +1 -1
- package/dist/{cli-pwwfxdgb.js → cli-rqh295j9.js} +15 -21
- package/dist/{index-x3ema2w3.js → cli-y6d1arem.js} +321 -272
- package/dist/cli.js +12 -12
- package/dist/{doctor-5gtpgpd1.js → doctor-ptb346k8.js} +4 -3
- package/dist/engine/shared/gcpm-extract.d.ts +8 -0
- package/dist/engine/shared/print-area.d.ts +16 -4
- package/dist/{engine-mc5br8g8.js → engine-4rzdx6af.js} +1 -1
- package/dist/{engine-tn13gk0b.js → engine-6txhxmmv.js} +2 -2
- package/dist/{ext-wn2a5afq.js → ext-gy8szg3x.js} +8 -8
- package/dist/{extension-restore-s3x1618g.js → extension-restore-dymzcasz.js} +2 -2
- package/dist/{extension-restore-g8jnmmzq.js → extension-restore-m8tj43e7.js} +4 -4
- package/dist/{gutterpress-viewer-701vf4qp.js → gutterpress-viewer-mafsby5k.js} +9 -2
- package/dist/{cli-2ppw6q9v.js → index-5crpmz42.js} +80 -1
- package/dist/{index-0skhjx3e.js → index-5kh4c78h.js} +19 -13
- package/dist/{index-2bjcghze.js → index-8ywkd2sv.js} +15 -21
- package/dist/{index-j5z86r4a.js → index-ea94zbq4.js} +329 -488
- package/dist/{cli-sdmv4bba.js → index-kaks3mm2.js} +448 -156
- package/dist/{index-4x6y8krm.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/extension-manager.d.ts +8 -7
- package/dist/lib/extension-manifest.d.ts +1 -13
- 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/manifest.d.ts +15 -1
- package/dist/lib/markdown/assemble.d.ts +4 -3
- 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 +45 -33
- package/dist/lib/pdf-inspect.d.ts +27 -0
- package/dist/lib/presets.d.ts +10 -8
- package/dist/lib/printsafe.d.ts +2 -1
- package/dist/lib/project-scaffold.d.ts +1 -1
- package/dist/lib/project-templates.d.ts +9 -0
- 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-2kc56wvw.yaml +22 -0
- package/dist/manifest-41ddzm13.yaml +18 -0
- package/dist/manifest-79zsgkpn.yaml +26 -0
- package/dist/manifest-sqzm4681.yaml +22 -0
- package/dist/{manifest.schema-t7nx2stg.json → manifest.schema-w86c1xw1.json} +30 -308
- package/dist/{new-mhs46pw3.js → new-t2t28ccb.js} +9 -15
- package/dist/{package-aenwjew3.json → package-awwkt7sa.json} +0 -1
- package/dist/{page-rules-nsj3aw42.css → page-rules-ytj9p04v.css} +12 -40
- package/dist/{pdf-inspect-wnw4za71.js → pdf-inspect-b3mf81ex.js} +3 -1
- package/dist/{plugin.test.js-xgxrd8hf.tpl → plugin.test.js-gxzqqfdh.tpl} +0 -1
- package/dist/{plugins-2cek4mz1.js → plugins-fec8t2bh.js} +1 -1
- package/dist/{plugins-1sxe0dkz.js → plugins-sqa4msdk.js} +3 -3
- package/dist/{preflight-3k2b1x8e.js → preflight-srq8fktp.js} +8 -8
- package/dist/preview/file-watcher.d.ts +1 -3
- package/dist/{preview-6p9v6rht.js → preview-zsp9hstd.js} +8 -8
- package/dist/{publish-qgsngy8s.js → publish-hhy31gr9.js} +8 -8
- package/dist/render.js +30 -562
- package/dist/schema/manifest.types.d.ts +60 -105
- package/dist/{tokens-7984461t.css → tokens-n82t4k9h.css} +12 -12
- package/dist/{validate-0v7xw6wa.js → validate-r9jdz85h.js} +8 -8
- package/package.json +1 -1
- package/dist/checks/asset/approved-fonts.d.ts +0 -3
- package/dist/manifest-eagfhba6.yaml +0 -19
- package/dist/manifest-n1gh3qw5.yaml +0 -9
|
@@ -8,17 +8,16 @@ import {
|
|
|
8
8
|
stampCreator,
|
|
9
9
|
stripAnnotations,
|
|
10
10
|
transparentPages
|
|
11
|
-
} from "./cli-
|
|
11
|
+
} from "./cli-d9mm3vvh.js";
|
|
12
12
|
import {
|
|
13
13
|
blackTextToGray
|
|
14
14
|
} from "./cli-ht1bcqdd.js";
|
|
15
15
|
import {
|
|
16
|
+
DEFAULT_PAGE_MARGIN_PT,
|
|
16
17
|
MARGIN_BOX_IGNORED_PROPERTIES,
|
|
17
|
-
extract,
|
|
18
18
|
getAssetPath,
|
|
19
|
-
lastPageMode
|
|
20
|
-
|
|
21
|
-
} from "./cli-pz4bn98t.js";
|
|
19
|
+
lastPageMode
|
|
20
|
+
} from "./cli-54xt7pjg.js";
|
|
22
21
|
import {
|
|
23
22
|
countLinkAnnotations,
|
|
24
23
|
getImageResolutions,
|
|
@@ -31,7 +30,7 @@ import {
|
|
|
31
30
|
loadPdf,
|
|
32
31
|
pageHasMarks,
|
|
33
32
|
retainPdfCache
|
|
34
|
-
} from "./cli-
|
|
33
|
+
} from "./cli-5crpmz42.js";
|
|
35
34
|
import {
|
|
36
35
|
INSTALL_HINTS,
|
|
37
36
|
execCapture,
|
|
@@ -57,11 +56,17 @@ import {
|
|
|
57
56
|
TARGET_IDS,
|
|
58
57
|
addExtension,
|
|
59
58
|
applyDefaultPdfStrictChecks,
|
|
59
|
+
cssLength,
|
|
60
60
|
ensureProjectGitignore,
|
|
61
|
+
formatPageSize,
|
|
62
|
+
isPositivePoints,
|
|
63
|
+
judgeRect,
|
|
61
64
|
loadManifest,
|
|
62
65
|
loadManifestDoc,
|
|
63
66
|
loadManifestWithPath,
|
|
64
67
|
npmRegistryUrl,
|
|
68
|
+
pageBoxes,
|
|
69
|
+
printAreaMeta,
|
|
65
70
|
publishTargetFor,
|
|
66
71
|
resolveConfig,
|
|
67
72
|
resolveConfigForTarget,
|
|
@@ -70,7 +75,7 @@ import {
|
|
|
70
75
|
uniqueExtensionId,
|
|
71
76
|
withFetchTimeout,
|
|
72
77
|
writeManifestDoc
|
|
73
|
-
} from "./cli-
|
|
78
|
+
} from "./cli-y6d1arem.js";
|
|
74
79
|
import {
|
|
75
80
|
EXTENSION_MANIFEST_FILENAME,
|
|
76
81
|
GUTTERPRESS_CSS,
|
|
@@ -91,7 +96,7 @@ import {
|
|
|
91
96
|
readExtensionMeta,
|
|
92
97
|
resolveDeclaredStyles,
|
|
93
98
|
slugify
|
|
94
|
-
} from "./cli-
|
|
99
|
+
} from "./cli-rqh295j9.js";
|
|
95
100
|
import {
|
|
96
101
|
PACKAGE_META,
|
|
97
102
|
PACKAGE_VERSION,
|
|
@@ -101,7 +106,7 @@ import {
|
|
|
101
106
|
log,
|
|
102
107
|
setLogLevel,
|
|
103
108
|
warn
|
|
104
|
-
} from "./cli-
|
|
109
|
+
} from "./cli-pspjxnc8.js";
|
|
105
110
|
import {
|
|
106
111
|
DEBOUNCE,
|
|
107
112
|
UsageError,
|
|
@@ -184,10 +189,7 @@ function selectorToRegex(selector) {
|
|
|
184
189
|
// src/checks/policy.ts
|
|
185
190
|
var INSPECT_FAILED_CODE = "inspect-failed";
|
|
186
191
|
function isCheckEnabled(check, config) {
|
|
187
|
-
|
|
188
|
-
if (entry === false)
|
|
189
|
-
return false;
|
|
190
|
-
if (typeof entry === "object" && entry.enabled === false)
|
|
192
|
+
if (config.checks[check.id] === "off")
|
|
191
193
|
return false;
|
|
192
194
|
if (check.enabledWhen && !check.enabledWhen(config))
|
|
193
195
|
return false;
|
|
@@ -281,84 +283,6 @@ var check2 = {
|
|
|
281
283
|
};
|
|
282
284
|
registerCheck(check2);
|
|
283
285
|
|
|
284
|
-
// src/engine/shared/print-area.ts
|
|
285
|
-
function isPositivePoints(value) {
|
|
286
|
-
return typeof value === "number" && Number.isFinite(value) && value > 0;
|
|
287
|
-
}
|
|
288
|
-
var round3 = (n) => Math.round(n * 1000) / 1000;
|
|
289
|
-
function cssLength(pt) {
|
|
290
|
-
const inches = round3(pt / 72);
|
|
291
|
-
return Math.abs(inches * 72 - pt) < 0.000001 ? `${inches}in` : `${round3(pt)}pt`;
|
|
292
|
-
}
|
|
293
|
-
function formatPageSize(page) {
|
|
294
|
-
return `${cssLength(page.width)} ${cssLength(page.height)}`;
|
|
295
|
-
}
|
|
296
|
-
function printAreaMeta(page) {
|
|
297
|
-
const area = JSON.stringify({
|
|
298
|
-
width: page.width,
|
|
299
|
-
height: page.height,
|
|
300
|
-
bleed: page.bleed ?? 0,
|
|
301
|
-
safe: page.safe ?? 0,
|
|
302
|
-
artSafe: page.artSafe,
|
|
303
|
-
gutter: page.gutter,
|
|
304
|
-
preset: page.preset,
|
|
305
|
-
spec: page.spec
|
|
306
|
-
});
|
|
307
|
-
return `<meta name="gp-print-area" content='${area.replace(/&/g, "&").replace(/'/g, "'")}'>`;
|
|
308
|
-
}
|
|
309
|
-
function pageBoxes(area, side, scale = 1) {
|
|
310
|
-
const w = area.width * scale;
|
|
311
|
-
const h = area.height * scale;
|
|
312
|
-
const b = Math.max(0, area.bleed) * scale;
|
|
313
|
-
const s = Math.max(0, area.safe) * scale;
|
|
314
|
-
const a = Math.max(0, area.artSafe) * scale;
|
|
315
|
-
const g = Math.max(0, area.gutter) * scale;
|
|
316
|
-
const [textLeft, textRight] = side === "verso" ? [s, g] : [g, s];
|
|
317
|
-
const [artLeft, artRight] = side === "verso" ? [a, g] : [g, a];
|
|
318
|
-
const trim = { x: side === "verso" ? b : 0, y: b, w: Math.max(0, w - b), h: Math.max(0, h - 2 * b) };
|
|
319
|
-
return {
|
|
320
|
-
sheet: { x: 0, y: 0, w, h },
|
|
321
|
-
trim,
|
|
322
|
-
safe: {
|
|
323
|
-
x: trim.x + textLeft,
|
|
324
|
-
y: trim.y + s,
|
|
325
|
-
w: Math.max(0, trim.w - textLeft - textRight),
|
|
326
|
-
h: Math.max(0, trim.h - 2 * s)
|
|
327
|
-
},
|
|
328
|
-
safeArt: {
|
|
329
|
-
x: trim.x + artLeft,
|
|
330
|
-
y: trim.y + a,
|
|
331
|
-
w: Math.max(0, trim.w - artLeft - artRight),
|
|
332
|
-
h: Math.max(0, trim.h - 2 * a)
|
|
333
|
-
},
|
|
334
|
-
bleed: b
|
|
335
|
-
};
|
|
336
|
-
}
|
|
337
|
-
var SEVERITY = { inside: 0, unsafe: 1, bleed: 2, "off-page": 3 };
|
|
338
|
-
function judgeRect(r, boxes, rule, tol = 0) {
|
|
339
|
-
const { sheet, trim } = boxes;
|
|
340
|
-
const safe = rule === "art" ? boxes.safeArt : boxes.safe;
|
|
341
|
-
const sides = [
|
|
342
|
-
["left", -r.x, -safe.x, -trim.x, -sheet.x],
|
|
343
|
-
["right", r.x + r.w, safe.x + safe.w, trim.x + trim.w, sheet.x + sheet.w],
|
|
344
|
-
["top", -r.y, -safe.y, -trim.y, -sheet.y],
|
|
345
|
-
["bottom", r.y + r.h, safe.y + safe.h, trim.y + trim.h, sheet.y + sheet.h]
|
|
346
|
-
];
|
|
347
|
-
let worst = { kind: "inside", gap: 0, need: 0, edge: null };
|
|
348
|
-
let beyond = 0;
|
|
349
|
-
for (const [edge, ink, limit, trimEdge, sheetEdge] of sides) {
|
|
350
|
-
const past = ink - limit;
|
|
351
|
-
if (past <= tol || rule === "art" && ink >= sheetEdge - tol)
|
|
352
|
-
continue;
|
|
353
|
-
const kind = ink > sheetEdge + tol ? "off-page" : ink > trimEdge + tol ? "bleed" : "unsafe";
|
|
354
|
-
if (SEVERITY[kind] > SEVERITY[worst.kind] || kind === worst.kind && past > beyond) {
|
|
355
|
-
worst = { kind, gap: trimEdge - ink, need: trimEdge - limit, edge };
|
|
356
|
-
beyond = past;
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
return worst;
|
|
360
|
-
}
|
|
361
|
-
|
|
362
286
|
// src/checks/pdf/safe-margins.ts
|
|
363
287
|
var TOLERANCE_PT = 0.5;
|
|
364
288
|
var ABOVE_BASELINE = 0.8;
|
|
@@ -846,7 +770,7 @@ var check8 = {
|
|
|
846
770
|
severity: "warning",
|
|
847
771
|
message: `Dark four-colour text at ${LARGE_TEXT_PT}pt or smaller on page(s) ${found.pages.join(", ")}.`,
|
|
848
772
|
file: ctx.pdfPath,
|
|
849
|
-
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 `
|
|
773
|
+
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.",
|
|
850
774
|
code: "rich-black-text",
|
|
851
775
|
data: { runs: found.runs, pages: found.pages }
|
|
852
776
|
})
|
|
@@ -926,8 +850,6 @@ var check10 = {
|
|
|
926
850
|
async run(ctx) {
|
|
927
851
|
if (!ctx.pdfPath)
|
|
928
852
|
return [];
|
|
929
|
-
if (!ctx.config.validate.pdf.requireBookmarks)
|
|
930
|
-
return [];
|
|
931
853
|
const doc = await loadPdf(ctx.pdfPath);
|
|
932
854
|
if (!doc) {
|
|
933
855
|
return [
|
|
@@ -960,8 +882,6 @@ var check11 = {
|
|
|
960
882
|
async run(ctx) {
|
|
961
883
|
if (!ctx.pdfPath)
|
|
962
884
|
return [];
|
|
963
|
-
if (!ctx.config.validate.pdf.requireTocLinks)
|
|
964
|
-
return [];
|
|
965
885
|
const doc = await loadPdf(ctx.pdfPath);
|
|
966
886
|
if (!doc) {
|
|
967
887
|
return [
|
|
@@ -1099,8 +1019,6 @@ var check15 = {
|
|
|
1099
1019
|
async run(ctx) {
|
|
1100
1020
|
if (!ctx.pdfPath)
|
|
1101
1021
|
return [];
|
|
1102
|
-
if (!ctx.config.validate.pdf.forbidTransparency)
|
|
1103
|
-
return [];
|
|
1104
1022
|
const bytes = await readPdfBytes(ctx.pdfPath).catch(() => "");
|
|
1105
1023
|
const found = [];
|
|
1106
1024
|
if (bytes.includes("/Transparency"))
|
|
@@ -1141,8 +1059,6 @@ var check16 = {
|
|
|
1141
1059
|
async run(ctx) {
|
|
1142
1060
|
if (!ctx.pdfPath)
|
|
1143
1061
|
return [];
|
|
1144
|
-
if (!ctx.config.validate.pdf.requireBleed)
|
|
1145
|
-
return [];
|
|
1146
1062
|
const bytes = await readPdfBytes(ctx.pdfPath).catch(() => "");
|
|
1147
1063
|
if (!bytes) {
|
|
1148
1064
|
return [
|
|
@@ -1233,18 +1149,20 @@ import { parse as parseYaml } from "yaml";
|
|
|
1233
1149
|
|
|
1234
1150
|
// src/checks/source/config-file.ts
|
|
1235
1151
|
import { existsSync } from "node:fs";
|
|
1236
|
-
import { resolve } from "node:path";
|
|
1237
|
-
function findConfigFile(
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1152
|
+
import { dirname, resolve } from "node:path";
|
|
1153
|
+
function findConfigFile(startDir, names) {
|
|
1154
|
+
let dir = resolve(startDir);
|
|
1155
|
+
for (;; ) {
|
|
1156
|
+
for (const name of names) {
|
|
1157
|
+
const p = resolve(dir, name);
|
|
1158
|
+
if (existsSync(p))
|
|
1159
|
+
return p;
|
|
1160
|
+
}
|
|
1161
|
+
const parent = dirname(dir);
|
|
1162
|
+
if (existsSync(resolve(dir, ".git")) || parent === dir)
|
|
1163
|
+
return null;
|
|
1164
|
+
dir = parent;
|
|
1246
1165
|
}
|
|
1247
|
-
return null;
|
|
1248
1166
|
}
|
|
1249
1167
|
|
|
1250
1168
|
// src/checks/source/markdownlint.ts
|
|
@@ -1286,17 +1204,13 @@ var check18 = {
|
|
|
1286
1204
|
category: "source",
|
|
1287
1205
|
phase: "pre-build",
|
|
1288
1206
|
async run(ctx) {
|
|
1289
|
-
const sourceConfig = ctx.config.validate.source;
|
|
1290
|
-
if (sourceConfig.markdownlint === false)
|
|
1291
|
-
return [];
|
|
1292
1207
|
const files = ctx.markdownFiles;
|
|
1293
1208
|
if (!files || files.length === 0)
|
|
1294
1209
|
return [];
|
|
1295
|
-
const
|
|
1296
|
-
|
|
1297
|
-
if (!resolvedConfig && !configPath)
|
|
1210
|
+
const resolvedConfig = findConfigFile(ctx.inputDir, CONFIG_NAMES);
|
|
1211
|
+
if (!resolvedConfig)
|
|
1298
1212
|
return [];
|
|
1299
|
-
const config =
|
|
1213
|
+
const config = await loadConfig(resolvedConfig);
|
|
1300
1214
|
const results = lint({ files, config });
|
|
1301
1215
|
const out = [];
|
|
1302
1216
|
for (const [file, violations] of Object.entries(results)) {
|
|
@@ -1332,14 +1246,10 @@ var check19 = {
|
|
|
1332
1246
|
category: "source",
|
|
1333
1247
|
phase: "pre-build",
|
|
1334
1248
|
async run(ctx) {
|
|
1335
|
-
const sourceConfig = ctx.config.validate.source;
|
|
1336
|
-
if (sourceConfig.htmlhint === false)
|
|
1337
|
-
return [];
|
|
1338
1249
|
if (!ctx.htmlPath || !existsSync2(ctx.htmlPath))
|
|
1339
1250
|
return [];
|
|
1340
|
-
const
|
|
1341
|
-
|
|
1342
|
-
if (!resolvedConfig && !configPath)
|
|
1251
|
+
const resolvedConfig = findConfigFile(ctx.inputDir, CONFIG_NAMES2);
|
|
1252
|
+
if (!resolvedConfig)
|
|
1343
1253
|
return [];
|
|
1344
1254
|
const ruleset = resolvedConfig ? JSON.parse(await readFile4(resolvedConfig, "utf8")) : HTMLHint.defaultRuleset;
|
|
1345
1255
|
const html = await readFile4(ctx.htmlPath, "utf8");
|
|
@@ -1367,7 +1277,7 @@ function ruleLevel(rules, id) {
|
|
|
1367
1277
|
const v = rules?.[id];
|
|
1368
1278
|
if (v === "off" || v === false)
|
|
1369
1279
|
return "off";
|
|
1370
|
-
if (v === "warn" || v === "warning")
|
|
1280
|
+
if (v === "warn" || v === "warning" || v === "info")
|
|
1371
1281
|
return "warn";
|
|
1372
1282
|
if (v === "error")
|
|
1373
1283
|
return "error";
|
|
@@ -1388,6 +1298,7 @@ var ruleRiskyProps = "printsafe/no-risky-print-effects";
|
|
|
1388
1298
|
var ruleSyntax = "printsafe/syntax-error";
|
|
1389
1299
|
var rulePageContainment = "printsafe/page-containment";
|
|
1390
1300
|
var rulePreviewCannotFollow = "printsafe/preview-cannot-follow";
|
|
1301
|
+
var rulePageSizeInStylesheet = "printsafe/page-size-in-stylesheet";
|
|
1391
1302
|
function extractUrls(value) {
|
|
1392
1303
|
const urls = [];
|
|
1393
1304
|
const re = /url\(\s*(['"]?)(.*?)\1\s*\)/gi;
|
|
@@ -1436,6 +1347,12 @@ function isInPageBox(decl) {
|
|
|
1436
1347
|
const page = decl.parent;
|
|
1437
1348
|
return !!page && page.type === "atrule" && page.name.toLowerCase() === "page";
|
|
1438
1349
|
}
|
|
1350
|
+
function isInBookPageRule(decl) {
|
|
1351
|
+
if (!isInPageBox(decl))
|
|
1352
|
+
return false;
|
|
1353
|
+
const params = decl.parent.params.trim();
|
|
1354
|
+
return params === "" || /^(:[a-z-]+\s*)+$/i.test(params);
|
|
1355
|
+
}
|
|
1439
1356
|
function isDroppedPageGradient(decl) {
|
|
1440
1357
|
const prop = decl.prop.toLowerCase();
|
|
1441
1358
|
if (prop !== "background" && prop !== "background-image")
|
|
@@ -1675,6 +1592,15 @@ function checkCssRaw(css, from) {
|
|
|
1675
1592
|
root.walkAtRules((at) => reportRemoteUrls(at.params || "", at));
|
|
1676
1593
|
root.walkDecls((decl) => {
|
|
1677
1594
|
const prop = decl.prop.toLowerCase();
|
|
1595
|
+
if (prop === "size" && isInBookPageRule(decl)) {
|
|
1596
|
+
warnings.push({
|
|
1597
|
+
rule: rulePageSizeInStylesheet,
|
|
1598
|
+
severity: "warning",
|
|
1599
|
+
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.`,
|
|
1600
|
+
...nodeLoc(decl)
|
|
1601
|
+
});
|
|
1602
|
+
return;
|
|
1603
|
+
}
|
|
1678
1604
|
if (isInertValue(prop, decl.value))
|
|
1679
1605
|
return;
|
|
1680
1606
|
if (marginBoxIgnoredProperties.has(prop) && isInPageMarginBox(decl)) {
|
|
@@ -1770,10 +1696,7 @@ var check20 = {
|
|
|
1770
1696
|
description: "Checks CSS for print-safety issues (remote URLs, rasterizing effects, and page-layer containment)",
|
|
1771
1697
|
category: "source",
|
|
1772
1698
|
phase: "pre-build",
|
|
1773
|
-
enabledWhen: (config) => config.validate.source.stylelint !== false,
|
|
1774
1699
|
async run(ctx) {
|
|
1775
|
-
if (ctx.config.validate.source.stylelint === false)
|
|
1776
|
-
return [];
|
|
1777
1700
|
const files = ctx.cssFiles;
|
|
1778
1701
|
if (!files || files.length === 0)
|
|
1779
1702
|
return [];
|
|
@@ -1791,7 +1714,7 @@ var check20 = {
|
|
|
1791
1714
|
});
|
|
1792
1715
|
continue;
|
|
1793
1716
|
}
|
|
1794
|
-
for (const w of checkCss(css, file, { rules: ctx.config.
|
|
1717
|
+
for (const w of checkCss(css, file, { rules: ctx.config.checks })) {
|
|
1795
1718
|
results.push({
|
|
1796
1719
|
checkId: check20.id,
|
|
1797
1720
|
severity: w.severity,
|
|
@@ -1987,15 +1910,11 @@ var check21 = {
|
|
|
1987
1910
|
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.",
|
|
1988
1911
|
category: "source",
|
|
1989
1912
|
phase: "pre-build",
|
|
1990
|
-
enabledWhen: (config) => config.validate.source.cssOwnership !== false,
|
|
1991
1913
|
async run(ctx) {
|
|
1992
|
-
if (ctx.config.validate.source.cssOwnership === false)
|
|
1993
|
-
return [];
|
|
1994
1914
|
const files = ctx.cssFiles;
|
|
1995
1915
|
if (!files || files.length === 0)
|
|
1996
1916
|
return [];
|
|
1997
|
-
const
|
|
1998
|
-
const configPath = findConfigFile(ctx.inputDir, CONFIG_NAMES3, explicit);
|
|
1917
|
+
const configPath = findConfigFile(ctx.inputDir, CONFIG_NAMES3);
|
|
1999
1918
|
if (!configPath)
|
|
2000
1919
|
return [];
|
|
2001
1920
|
let contract;
|
|
@@ -2062,7 +1981,7 @@ registerCheck(check21);
|
|
|
2062
1981
|
|
|
2063
1982
|
// src/checks/source/local-refs.ts
|
|
2064
1983
|
import { existsSync as existsSync4 } from "node:fs";
|
|
2065
|
-
import { dirname, resolve as resolve2 } from "node:path";
|
|
1984
|
+
import { dirname as dirname2, resolve as resolve2 } from "node:path";
|
|
2066
1985
|
|
|
2067
1986
|
// src/lib/asset-inline.ts
|
|
2068
1987
|
import { createHash } from "node:crypto";
|
|
@@ -2488,7 +2407,7 @@ function filesystemRef(ref) {
|
|
|
2488
2407
|
}
|
|
2489
2408
|
function localRefExists(ref, kind, sourceFile, projectRoot) {
|
|
2490
2409
|
const cleaned = filesystemRef(ref);
|
|
2491
|
-
const fileRelative = resolve2(
|
|
2410
|
+
const fileRelative = resolve2(dirname2(sourceFile), cleaned);
|
|
2492
2411
|
const rootRelative = resolve2(projectRoot, cleaned);
|
|
2493
2412
|
switch (kind) {
|
|
2494
2413
|
case "image":
|
|
@@ -3590,8 +3509,6 @@ var check30 = {
|
|
|
3590
3509
|
category: "asset",
|
|
3591
3510
|
phase: "pre-build",
|
|
3592
3511
|
async run(ctx) {
|
|
3593
|
-
if (ctx.config.validate.assets.allowAlpha)
|
|
3594
|
-
return [];
|
|
3595
3512
|
if (ctx.config.pdfx.transparency === "preserve-text")
|
|
3596
3513
|
return [];
|
|
3597
3514
|
const files = shippedImages(ctx, ["png", "tiff", "tif"]);
|
|
@@ -3614,58 +3531,6 @@ var check30 = {
|
|
|
3614
3531
|
};
|
|
3615
3532
|
registerCheck(check30);
|
|
3616
3533
|
|
|
3617
|
-
// src/checks/asset/approved-fonts.ts
|
|
3618
|
-
var check31 = {
|
|
3619
|
-
id: "asset.font.approved-files",
|
|
3620
|
-
name: "Approved Font Files",
|
|
3621
|
-
description: "Checks font files against the approved file patterns",
|
|
3622
|
-
category: "asset",
|
|
3623
|
-
phase: "pre-build",
|
|
3624
|
-
async run(ctx) {
|
|
3625
|
-
const patterns = ctx.config.validate.assets.approvedFontFiles;
|
|
3626
|
-
if (!patterns || patterns.length === 0)
|
|
3627
|
-
return [];
|
|
3628
|
-
const { glob } = await import("glob");
|
|
3629
|
-
const dirs = ctx.assetDirs ?? [ctx.inputDir];
|
|
3630
|
-
const allFonts = [];
|
|
3631
|
-
for (const dir of dirs) {
|
|
3632
|
-
const matches = await glob(`**/*.{${FONT_EXTS2.join(",")}}`, {
|
|
3633
|
-
cwd: dir,
|
|
3634
|
-
absolute: true,
|
|
3635
|
-
ignore: [...ASSET_SCAN_IGNORE_GLOBS]
|
|
3636
|
-
});
|
|
3637
|
-
allFonts.push(...matches);
|
|
3638
|
-
}
|
|
3639
|
-
if (allFonts.length === 0)
|
|
3640
|
-
return [];
|
|
3641
|
-
const approvedFonts = new Set;
|
|
3642
|
-
for (const dir of dirs) {
|
|
3643
|
-
for (const pattern of patterns) {
|
|
3644
|
-
const matches = await glob(pattern, {
|
|
3645
|
-
cwd: dir,
|
|
3646
|
-
absolute: true,
|
|
3647
|
-
ignore: [...ASSET_SCAN_IGNORE_GLOBS]
|
|
3648
|
-
});
|
|
3649
|
-
for (const m of matches)
|
|
3650
|
-
approvedFonts.add(m);
|
|
3651
|
-
}
|
|
3652
|
-
}
|
|
3653
|
-
const results = [];
|
|
3654
|
-
for (const font of allFonts) {
|
|
3655
|
-
if (!approvedFonts.has(font)) {
|
|
3656
|
-
results.push({
|
|
3657
|
-
checkId: check31.id,
|
|
3658
|
-
severity: "warning",
|
|
3659
|
-
message: "Font file not in approved list",
|
|
3660
|
-
file: font
|
|
3661
|
-
});
|
|
3662
|
-
}
|
|
3663
|
-
}
|
|
3664
|
-
return results;
|
|
3665
|
-
}
|
|
3666
|
-
};
|
|
3667
|
-
registerCheck(check31);
|
|
3668
|
-
|
|
3669
3534
|
// src/checks/asset/font-license.ts
|
|
3670
3535
|
import { existsSync as existsSync5 } from "node:fs";
|
|
3671
3536
|
import { resolve as resolve3 } from "node:path";
|
|
@@ -3679,15 +3544,13 @@ var LICENSE_NAMES = [
|
|
|
3679
3544
|
"OFL-1.1.txt",
|
|
3680
3545
|
"COPYING"
|
|
3681
3546
|
];
|
|
3682
|
-
var
|
|
3547
|
+
var check31 = {
|
|
3683
3548
|
id: "asset.font.license",
|
|
3684
3549
|
name: "Font License",
|
|
3685
3550
|
description: "Checks for license files in font directories",
|
|
3686
3551
|
category: "asset",
|
|
3687
3552
|
phase: "pre-build",
|
|
3688
3553
|
async run(ctx) {
|
|
3689
|
-
if (!ctx.config.validate.assets.requireFontLicense)
|
|
3690
|
-
return [];
|
|
3691
3554
|
const { glob } = await import("glob");
|
|
3692
3555
|
const dirs = ctx.assetDirs ?? [ctx.inputDir];
|
|
3693
3556
|
const fontDirs = new Set;
|
|
@@ -3706,7 +3569,7 @@ var check32 = {
|
|
|
3706
3569
|
const hasLicense = LICENSE_NAMES.some((name) => existsSync5(resolve3(fontDir, name)));
|
|
3707
3570
|
if (!hasLicense) {
|
|
3708
3571
|
results.push({
|
|
3709
|
-
checkId:
|
|
3572
|
+
checkId: check31.id,
|
|
3710
3573
|
severity: "warning",
|
|
3711
3574
|
message: `No font license file found in directory`,
|
|
3712
3575
|
file: fontDir
|
|
@@ -3716,10 +3579,10 @@ var check32 = {
|
|
|
3716
3579
|
return results;
|
|
3717
3580
|
}
|
|
3718
3581
|
};
|
|
3719
|
-
registerCheck(
|
|
3582
|
+
registerCheck(check31);
|
|
3720
3583
|
|
|
3721
3584
|
// src/checks/heuristic/text-density.ts
|
|
3722
|
-
var
|
|
3585
|
+
var check32 = {
|
|
3723
3586
|
id: "heuristic.whitespace.text-density",
|
|
3724
3587
|
name: "Text Density",
|
|
3725
3588
|
description: "Checks characters-per-page ratio",
|
|
@@ -3748,7 +3611,7 @@ var check33 = {
|
|
|
3748
3611
|
});
|
|
3749
3612
|
if (lowPages.length > 0) {
|
|
3750
3613
|
results.push({
|
|
3751
|
-
checkId:
|
|
3614
|
+
checkId: check32.id,
|
|
3752
3615
|
severity: "info",
|
|
3753
3616
|
message: `Low text density on pages: ${lowPages.join(", ")} (below ${range.min} chars)`,
|
|
3754
3617
|
file: ctx.pdfPath
|
|
@@ -3756,7 +3619,7 @@ var check33 = {
|
|
|
3756
3619
|
}
|
|
3757
3620
|
if (highPages.length > 0) {
|
|
3758
3621
|
results.push({
|
|
3759
|
-
checkId:
|
|
3622
|
+
checkId: check32.id,
|
|
3760
3623
|
severity: "info",
|
|
3761
3624
|
message: `High text density on pages: ${highPages.join(", ")} (above ${range.max} chars)`,
|
|
3762
3625
|
file: ctx.pdfPath
|
|
@@ -3765,11 +3628,11 @@ var check33 = {
|
|
|
3765
3628
|
return results;
|
|
3766
3629
|
}
|
|
3767
3630
|
};
|
|
3768
|
-
registerCheck(
|
|
3631
|
+
registerCheck(check32);
|
|
3769
3632
|
|
|
3770
3633
|
// src/checks/heuristic/section-density.ts
|
|
3771
3634
|
import { readFile as readFile15 } from "node:fs/promises";
|
|
3772
|
-
var
|
|
3635
|
+
var check33 = {
|
|
3773
3636
|
id: "heuristic.chunking.section-density",
|
|
3774
3637
|
name: "Section Density",
|
|
3775
3638
|
description: "Checks heading/paragraph/callout density from source Markdown",
|
|
@@ -3795,7 +3658,7 @@ var check34 = {
|
|
|
3795
3658
|
const line = lines[i];
|
|
3796
3659
|
if (/^#{1,6}\s/.test(line)) {
|
|
3797
3660
|
if (paragraphCount > maxParas) {
|
|
3798
|
-
results.push(finding(
|
|
3661
|
+
results.push(finding(check33.id, {
|
|
3799
3662
|
severity: "info",
|
|
3800
3663
|
message: `Section has ${paragraphCount} paragraphs (max recommended: ${maxParas})`,
|
|
3801
3664
|
file,
|
|
@@ -3815,7 +3678,7 @@ var check34 = {
|
|
|
3815
3678
|
}
|
|
3816
3679
|
}
|
|
3817
3680
|
if (paragraphCount > maxParas) {
|
|
3818
|
-
results.push(finding(
|
|
3681
|
+
results.push(finding(check33.id, {
|
|
3819
3682
|
severity: "info",
|
|
3820
3683
|
message: `Section has ${paragraphCount} paragraphs (max recommended: ${maxParas})`,
|
|
3821
3684
|
file,
|
|
@@ -3823,7 +3686,7 @@ var check34 = {
|
|
|
3823
3686
|
}));
|
|
3824
3687
|
}
|
|
3825
3688
|
} catch {
|
|
3826
|
-
results.push(inspectionFailed(
|
|
3689
|
+
results.push(inspectionFailed(check33.id, `Could not read source file: ${file}`, {
|
|
3827
3690
|
file
|
|
3828
3691
|
}));
|
|
3829
3692
|
}
|
|
@@ -3831,10 +3694,10 @@ var check34 = {
|
|
|
3831
3694
|
return results;
|
|
3832
3695
|
}
|
|
3833
3696
|
};
|
|
3834
|
-
registerCheck(
|
|
3697
|
+
registerCheck(check33);
|
|
3835
3698
|
|
|
3836
3699
|
// src/checks/heuristic/layer-count.ts
|
|
3837
|
-
var
|
|
3700
|
+
var check34 = {
|
|
3838
3701
|
id: "heuristic.decoration.layer-count",
|
|
3839
3702
|
name: "Layer Count",
|
|
3840
3703
|
description: "Counts image objects per page",
|
|
@@ -3859,7 +3722,7 @@ var check35 = {
|
|
|
3859
3722
|
heavyPages.sort((a, b) => a - b);
|
|
3860
3723
|
return [
|
|
3861
3724
|
{
|
|
3862
|
-
checkId:
|
|
3725
|
+
checkId: check34.id,
|
|
3863
3726
|
severity: "info",
|
|
3864
3727
|
message: `Pages with many image layers (>${maxLayers}): ${heavyPages.join(", ")}`,
|
|
3865
3728
|
file: ctx.pdfPath
|
|
@@ -3869,10 +3732,10 @@ var check35 = {
|
|
|
3869
3732
|
return [];
|
|
3870
3733
|
}
|
|
3871
3734
|
};
|
|
3872
|
-
registerCheck(
|
|
3735
|
+
registerCheck(check34);
|
|
3873
3736
|
|
|
3874
3737
|
// src/checks/heuristic/placement-variance.ts
|
|
3875
|
-
var
|
|
3738
|
+
var check35 = {
|
|
3876
3739
|
id: "heuristic.layout.placement-variance",
|
|
3877
3740
|
name: "Placement Variance",
|
|
3878
3741
|
description: "Analyzes text baseline coordinates for layout consistency",
|
|
@@ -3890,7 +3753,7 @@ var check36 = {
|
|
|
3890
3753
|
const uniqueX = new Set(positions.map((p) => Math.round(p.x)));
|
|
3891
3754
|
return [
|
|
3892
3755
|
{
|
|
3893
|
-
checkId:
|
|
3756
|
+
checkId: check35.id,
|
|
3894
3757
|
severity: "info",
|
|
3895
3758
|
message: `Layout analysis: ${uniqueX.size} unique horizontal text positions across ${positions.length} text blocks.`,
|
|
3896
3759
|
file: ctx.pdfPath
|
|
@@ -3898,21 +3761,21 @@ var check36 = {
|
|
|
3898
3761
|
];
|
|
3899
3762
|
}
|
|
3900
3763
|
};
|
|
3901
|
-
registerCheck(
|
|
3764
|
+
registerCheck(check35);
|
|
3902
3765
|
|
|
3903
3766
|
// src/checks/tool-check.ts
|
|
3904
3767
|
async function checkToolAvailability(config, opts = {}) {
|
|
3905
3768
|
const { checks: checks2 } = selectChecks(opts, config);
|
|
3906
3769
|
const toolToChecks = new Map;
|
|
3907
|
-
for (const
|
|
3908
|
-
if (!
|
|
3770
|
+
for (const check36 of checks2) {
|
|
3771
|
+
if (!check36.requiredTools?.length)
|
|
3909
3772
|
continue;
|
|
3910
|
-
for (const tool of
|
|
3773
|
+
for (const tool of check36.requiredTools) {
|
|
3911
3774
|
const existing = toolToChecks.get(tool);
|
|
3912
3775
|
if (existing) {
|
|
3913
|
-
existing.push(
|
|
3776
|
+
existing.push(check36.id);
|
|
3914
3777
|
} else {
|
|
3915
|
-
toolToChecks.set(tool, [
|
|
3778
|
+
toolToChecks.set(tool, [check36.id]);
|
|
3916
3779
|
}
|
|
3917
3780
|
}
|
|
3918
3781
|
}
|
|
@@ -3928,11 +3791,11 @@ async function checkToolAvailability(config, opts = {}) {
|
|
|
3928
3791
|
const missing = results.filter((r) => !r.found).map((r) => r.tool);
|
|
3929
3792
|
const missingSet = new Set(missing);
|
|
3930
3793
|
const skippedChecks = [];
|
|
3931
|
-
for (const
|
|
3932
|
-
if (!
|
|
3794
|
+
for (const check36 of checks2) {
|
|
3795
|
+
if (!check36.requiredTools?.length)
|
|
3933
3796
|
continue;
|
|
3934
|
-
if (
|
|
3935
|
-
skippedChecks.push(
|
|
3797
|
+
if (check36.requiredTools.some((t) => missingSet.has(t))) {
|
|
3798
|
+
skippedChecks.push(check36.id);
|
|
3936
3799
|
}
|
|
3937
3800
|
}
|
|
3938
3801
|
return { available, missing, skippedChecks, toolToChecks };
|
|
@@ -3952,7 +3815,7 @@ function reportMissingTools(result) {
|
|
|
3952
3815
|
// src/lib/validation-exec.ts
|
|
3953
3816
|
import { existsSync as existsSync6 } from "node:fs";
|
|
3954
3817
|
import { readFile as readFile18 } from "node:fs/promises";
|
|
3955
|
-
import { dirname as
|
|
3818
|
+
import { dirname as dirname3, join as join2, resolve as resolve4 } from "node:path";
|
|
3956
3819
|
|
|
3957
3820
|
// src/lib/output-paths.ts
|
|
3958
3821
|
import path5 from "node:path";
|
|
@@ -3995,16 +3858,25 @@ function canonicalChapterId(p) {
|
|
|
3995
3858
|
}
|
|
3996
3859
|
|
|
3997
3860
|
// src/lib/markdown/assemble.ts
|
|
3998
|
-
function
|
|
3861
|
+
function pageGeometryCss(page) {
|
|
3999
3862
|
if (!page || !isPositivePoints(page.width) || !isPositivePoints(page.height))
|
|
4000
3863
|
return null;
|
|
4001
|
-
|
|
4002
|
-
|
|
4003
|
-
|
|
4004
|
-
|
|
3864
|
+
const size2 = `size: ${formatPageSize(page)};`;
|
|
3865
|
+
const m = page.margin;
|
|
3866
|
+
if (!m)
|
|
3867
|
+
return `@page { ${size2} }`;
|
|
3868
|
+
const [top, bottom, inside, outside] = [m.top, m.bottom, m.inside, m.outside].map(cssLength);
|
|
3869
|
+
const recto = `margin: ${top} ${outside} ${bottom} ${inside};`;
|
|
3870
|
+
const verso = `margin: ${top} ${inside} ${bottom} ${outside};`;
|
|
3871
|
+
return [`@page { ${size2} ${recto} }`, `@page :left { ${verso} }`, `@page :right { ${recto} }`].join(`
|
|
3872
|
+
`);
|
|
3873
|
+
}
|
|
3874
|
+
function defaultPageMarginCss(page) {
|
|
3875
|
+
if (!page || page.margin)
|
|
4005
3876
|
return null;
|
|
4006
|
-
|
|
4007
|
-
|
|
3877
|
+
return `@layer gp.vocab {
|
|
3878
|
+
@page { margin: ${cssLength(DEFAULT_PAGE_MARGIN_PT)}; }
|
|
3879
|
+
}`;
|
|
4008
3880
|
}
|
|
4009
3881
|
async function assembleBookHtml(opts) {
|
|
4010
3882
|
const title = opts.title ?? "Document";
|
|
@@ -4044,8 +3916,8 @@ async function assembleBookHtml(opts) {
|
|
|
4044
3916
|
imageRefs.add(ref);
|
|
4045
3917
|
opts.onImageRefs([...imageRefs]);
|
|
4046
3918
|
}
|
|
4047
|
-
const
|
|
4048
|
-
|
|
3919
|
+
const pageGeometry = pageGeometryCss(opts.printArea);
|
|
3920
|
+
const defaultMargin = defaultPageMarginCss(opts.printArea);
|
|
4049
3921
|
const inlineCss = [
|
|
4050
3922
|
"@layer gp.marker, gp.vocab;",
|
|
4051
3923
|
`/* gutterpress markers */
|
|
@@ -4057,14 +3929,16 @@ ${TWO_VERSIONS_CSS.trim()}
|
|
|
4057
3929
|
@layer gp.vocab {
|
|
4058
3930
|
${GUTTERPRESS_CSS.trim()}
|
|
4059
3931
|
}`,
|
|
4060
|
-
|
|
4061
|
-
${
|
|
3932
|
+
defaultMargin ? `/* page margins (default) */
|
|
3933
|
+
${defaultMargin}` : null,
|
|
4062
3934
|
pluginCss ? `/* extension css */
|
|
4063
3935
|
${pluginCss.trim()}` : null,
|
|
4064
3936
|
`/* column alignment */
|
|
4065
3937
|
${TABLE_ALIGN_CSS.trim()}`,
|
|
4066
3938
|
projectCss ? `/* project css */
|
|
4067
|
-
${projectCss.trim()}` : null
|
|
3939
|
+
${projectCss.trim()}` : null,
|
|
3940
|
+
pageGeometry ? `/* page geometry (manifest) */
|
|
3941
|
+
${pageGeometry}` : null
|
|
4068
3942
|
].filter(Boolean).join(`
|
|
4069
3943
|
|
|
4070
3944
|
`);
|
|
@@ -4186,8 +4060,7 @@ async function uncommittedAmong(inputDir, files) {
|
|
|
4186
4060
|
return files.filter((file) => changed.has(repoSubPath(repoRoot, file)));
|
|
4187
4061
|
}
|
|
4188
4062
|
async function applyMarkdownlintFixes(ctx) {
|
|
4189
|
-
|
|
4190
|
-
if (sourceConfig.markdownlint === false) {
|
|
4063
|
+
if (ctx.config.checks["source.markdownlint"] === "off") {
|
|
4191
4064
|
log.warn("--fix: source.markdownlint is disabled for this book — no files were fixed.");
|
|
4192
4065
|
return [];
|
|
4193
4066
|
}
|
|
@@ -4196,13 +4069,12 @@ async function applyMarkdownlintFixes(ctx) {
|
|
|
4196
4069
|
log.warn("--fix: no markdown files to fix.");
|
|
4197
4070
|
return [];
|
|
4198
4071
|
}
|
|
4199
|
-
const
|
|
4200
|
-
|
|
4201
|
-
|
|
4202
|
-
log.warn(`--fix: no markdownlint config found in ${ctx.inputDir} (looked for ${CONFIG_NAMES.join(", ")}) — no files were fixed.`);
|
|
4072
|
+
const resolvedConfig = findConfigFile(ctx.inputDir, CONFIG_NAMES);
|
|
4073
|
+
if (!resolvedConfig) {
|
|
4074
|
+
log.warn(`--fix: no markdownlint config found in ${ctx.inputDir} or a folder above it (looked for ${CONFIG_NAMES.join(", ")}) — no files were fixed.`);
|
|
4203
4075
|
return [];
|
|
4204
4076
|
}
|
|
4205
|
-
const config =
|
|
4077
|
+
const config = await loadConfig(resolvedConfig);
|
|
4206
4078
|
const results = lint2({ files, config });
|
|
4207
4079
|
const pending = [];
|
|
4208
4080
|
for (const [file, violations] of Object.entries(results)) {
|
|
@@ -4291,15 +4163,10 @@ function formatLocation(file, line, column) {
|
|
|
4291
4163
|
|
|
4292
4164
|
// src/checks/runner.ts
|
|
4293
4165
|
function getCheckSeverityOverride(checkId, config) {
|
|
4294
|
-
const
|
|
4295
|
-
|
|
4296
|
-
return entry.severity;
|
|
4297
|
-
return;
|
|
4166
|
+
const level = config.checks[checkId];
|
|
4167
|
+
return level === "off" || level === "on" ? undefined : level;
|
|
4298
4168
|
}
|
|
4299
4169
|
async function runChecks(ctx, opts = {}) {
|
|
4300
|
-
if (ctx.config.validate.enabled === false) {
|
|
4301
|
-
return emptyReport();
|
|
4302
|
-
}
|
|
4303
4170
|
const { checks: selected, unmatched: unmatchedSelectors } = selectChecks(opts, ctx.config);
|
|
4304
4171
|
let checks2 = selected;
|
|
4305
4172
|
if (opts.skipMissingTools && opts.skipMissingTools.length > 0) {
|
|
@@ -4317,32 +4184,25 @@ async function runChecks(ctx, opts = {}) {
|
|
|
4317
4184
|
}
|
|
4318
4185
|
const release = retainPdfCache();
|
|
4319
4186
|
try {
|
|
4320
|
-
for (const
|
|
4187
|
+
for (const check36 of checks2) {
|
|
4321
4188
|
try {
|
|
4322
|
-
|
|
4323
|
-
const severityOverride = getCheckSeverityOverride(
|
|
4189
|
+
const results = await check36.run(ctx);
|
|
4190
|
+
const severityOverride = getCheckSeverityOverride(check36.id, ctx.config);
|
|
4324
4191
|
if (severityOverride) {
|
|
4325
4192
|
for (const r of results) {
|
|
4326
4193
|
r.severity = severityOverride;
|
|
4327
4194
|
}
|
|
4328
4195
|
}
|
|
4329
|
-
const lintLevel = ruleLevel(ctx.config.lint.rules, check37.id);
|
|
4330
|
-
if (lintLevel === "off")
|
|
4331
|
-
results = [];
|
|
4332
|
-
else if (lintLevel) {
|
|
4333
|
-
for (const r of results)
|
|
4334
|
-
r.severity = lintLevel === "warn" ? "warning" : "error";
|
|
4335
|
-
}
|
|
4336
4196
|
if (results.length === 0) {
|
|
4337
|
-
passed.push(
|
|
4197
|
+
passed.push(check36.id);
|
|
4338
4198
|
} else {
|
|
4339
4199
|
allResults.push(...results);
|
|
4340
4200
|
}
|
|
4341
4201
|
} catch (err) {
|
|
4342
4202
|
allResults.push({
|
|
4343
|
-
checkId:
|
|
4203
|
+
checkId: check36.id,
|
|
4344
4204
|
severity: "error",
|
|
4345
|
-
message: `Check "${
|
|
4205
|
+
message: `Check "${check36.id}" threw: ${err instanceof Error ? err.message : String(err)}`
|
|
4346
4206
|
});
|
|
4347
4207
|
}
|
|
4348
4208
|
}
|
|
@@ -4367,16 +4227,6 @@ async function runChecks(ctx, opts = {}) {
|
|
|
4367
4227
|
}
|
|
4368
4228
|
};
|
|
4369
4229
|
}
|
|
4370
|
-
function emptyReport() {
|
|
4371
|
-
return {
|
|
4372
|
-
results: [],
|
|
4373
|
-
errors: [],
|
|
4374
|
-
warnings: [],
|
|
4375
|
-
infos: [],
|
|
4376
|
-
passed: [],
|
|
4377
|
-
summary: { total: 0, errors: 0, warnings: 0, infos: 0, passed: 0 }
|
|
4378
|
-
};
|
|
4379
|
-
}
|
|
4380
4230
|
|
|
4381
4231
|
// src/lib/validation-exec.ts
|
|
4382
4232
|
var SHIPPED_ASSET_EXTS = new Set([
|
|
@@ -4432,7 +4282,7 @@ async function sharedAssetDirs(manifestDir, relStyles, inputDir) {
|
|
|
4432
4282
|
const ext = file.slice(file.lastIndexOf(".")).toLowerCase();
|
|
4433
4283
|
if (!SHIPPED_ASSET_EXTS.has(ext))
|
|
4434
4284
|
continue;
|
|
4435
|
-
const dir =
|
|
4285
|
+
const dir = dirname3(resolve4(file));
|
|
4436
4286
|
if (escapesProjectRoot(projectRoot, dir))
|
|
4437
4287
|
dirs.add(dir);
|
|
4438
4288
|
}
|
|
@@ -4593,7 +4443,7 @@ function planRuns(opts) {
|
|
|
4593
4443
|
async function executeValidation(args) {
|
|
4594
4444
|
const manifestPath = typeof args.manifest === "string" ? args.manifest : undefined;
|
|
4595
4445
|
const { manifest, manifestDir } = await loadManifestWithPath(manifestPath ?? args.input ?? undefined, { explicit: manifestPath !== undefined });
|
|
4596
|
-
const config = resolveConfig(args.skipStylelint ? {
|
|
4446
|
+
const config = resolveConfig(args.skipStylelint ? { checks: { "source.stylelint": "off" } } : {}, manifest);
|
|
4597
4447
|
const targetIds = resolveTargets(parseCsv(typeof args.target === "string" ? args.target : undefined), config.targets);
|
|
4598
4448
|
const pdfPath = typeof args.pdf === "string" ? resolve4(args.pdf) : undefined;
|
|
4599
4449
|
const inputDir = typeof args.input === "string" ? resolve4(args.input) : undefined;
|
|
@@ -4626,7 +4476,7 @@ async function executeValidation(args) {
|
|
|
4626
4476
|
let htmlPath;
|
|
4627
4477
|
const outDir = resolveOutputDir(manifestDir, config.title);
|
|
4628
4478
|
if (inputDir) {
|
|
4629
|
-
const relMarkdown = await resolveActiveMarkdownFiles(manifestDir, config.
|
|
4479
|
+
const relMarkdown = await resolveActiveMarkdownFiles(manifestDir, config.chapters);
|
|
4630
4480
|
markdownFiles = relMarkdown.map((f) => join2(manifestDir, canonicalChapterId(f)));
|
|
4631
4481
|
const relStyles = await resolveActiveStyles(manifestDir, config.styles);
|
|
4632
4482
|
const projectCssFiles = relStyles.map((rel) => resolve4(manifestDir, rel));
|
|
@@ -4662,7 +4512,7 @@ async function executeValidation(args) {
|
|
|
4662
4512
|
};
|
|
4663
4513
|
if (args.fix) {
|
|
4664
4514
|
const selected = selectChecks(runnerOptions, config).checks;
|
|
4665
|
-
if (selected.some((
|
|
4515
|
+
if (selected.some((check36) => check36.id === MARKDOWNLINT_CHECK_ID)) {
|
|
4666
4516
|
await applyMarkdownlintFixes(context);
|
|
4667
4517
|
} else {
|
|
4668
4518
|
log.warn(`--fix: ${MARKDOWNLINT_CHECK_ID} is not part of this run — no files were fixed.`);
|
|
@@ -4940,16 +4790,16 @@ ${list}
|
|
|
4940
4790
|
|
|
4941
4791
|
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);
|
|
4942
4792
|
}
|
|
4943
|
-
function computeGates(format, opts
|
|
4793
|
+
function computeGates(format, opts) {
|
|
4944
4794
|
if (format === "html") {
|
|
4945
4795
|
if (opts.skipLint || opts.skipPreValidate || opts.skipPostValidate) {
|
|
4946
4796
|
log.info("Validation/lint flags ignored for --format html (no validation phases apply)");
|
|
4947
4797
|
}
|
|
4948
4798
|
return { skipStylelint: false, preValidate: false, postValidate: false };
|
|
4949
4799
|
}
|
|
4950
|
-
const skipStylelint = !!opts.skipLint
|
|
4951
|
-
const preValidate = !opts.skipPreValidate
|
|
4952
|
-
const postValidate = format === "pdfx" && !opts.skipPostValidate
|
|
4800
|
+
const skipStylelint = !!opts.skipLint;
|
|
4801
|
+
const preValidate = !opts.skipPreValidate;
|
|
4802
|
+
const postValidate = format === "pdfx" && !opts.skipPostValidate;
|
|
4953
4803
|
return { skipStylelint, preValidate, postValidate };
|
|
4954
4804
|
}
|
|
4955
4805
|
|
|
@@ -4985,7 +4835,7 @@ async function resolveBuildContext(opts) {
|
|
|
4985
4835
|
}, manifest);
|
|
4986
4836
|
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) };
|
|
4987
4837
|
const outDir = target.kind === "file" ? path7.dirname(target.file) : target.dir;
|
|
4988
|
-
const gates = computeGates(format, opts
|
|
4838
|
+
const gates = computeGates(format, opts);
|
|
4989
4839
|
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")}`);
|
|
4990
4840
|
return {
|
|
4991
4841
|
opts,
|
|
@@ -5041,8 +4891,8 @@ async function runQualityGates(ctx) {
|
|
|
5041
4891
|
}
|
|
5042
4892
|
async function renderBook(ctx) {
|
|
5043
4893
|
const { config, gates, renderDir, workDir, opts, format } = ctx;
|
|
5044
|
-
if (config.
|
|
5045
|
-
log.info(`Using specified files (${config.
|
|
4894
|
+
if (config.chapters && config.chapters.length > 0) {
|
|
4895
|
+
log.info(`Using specified files (${config.chapters.length} total)`);
|
|
5046
4896
|
} else {
|
|
5047
4897
|
log.info("Using all .md files in alphabetical order");
|
|
5048
4898
|
}
|
|
@@ -5055,7 +4905,7 @@ async function renderBook(ctx) {
|
|
|
5055
4905
|
print: config.print,
|
|
5056
4906
|
printArea: { ...config.page, preset: config.preset, spec: config.spec },
|
|
5057
4907
|
styles: config.styles,
|
|
5058
|
-
files: config.
|
|
4908
|
+
files: config.chapters,
|
|
5059
4909
|
plugins,
|
|
5060
4910
|
pluginStyles,
|
|
5061
4911
|
onChapterWarnings: (file, warnings) => {
|
|
@@ -5206,7 +5056,7 @@ class PdfOutput {
|
|
|
5206
5056
|
const rawPdf = pdfxMode ? path7.join(stage, "raw.pdf") : path7.resolve(pdfFile);
|
|
5207
5057
|
await fsp2.mkdir(path7.dirname(path7.resolve(pdfFile)), { recursive: true });
|
|
5208
5058
|
log.info("Rendering HTML to PDF via the Gutterpress engine (native Chromium pagination)");
|
|
5209
|
-
const { buildNativePdf } = await import("./engine-
|
|
5059
|
+
const { buildNativePdf } = await import("./engine-4rzdx6af.js");
|
|
5210
5060
|
const engineDiagnostics = await buildNativePdf(htmlFile, rawPdf, {
|
|
5211
5061
|
title: config.title,
|
|
5212
5062
|
author: config.authors.length > 0 ? config.authors.join(", ") : undefined,
|
|
@@ -5243,7 +5093,7 @@ class PdfOutput {
|
|
|
5243
5093
|
}
|
|
5244
5094
|
const flattenPages = config.pdfx.flattenPages;
|
|
5245
5095
|
if (transparent.length > 0 && config.pdfx.transparency === "preserve-text") {
|
|
5246
|
-
const { unsplittableTextReasons } = await import("./pdf-inspect-
|
|
5096
|
+
const { unsplittableTextReasons } = await import("./pdf-inspect-b3mf81ex.js");
|
|
5247
5097
|
const reasons = await unsplittableTextReasons(rawBytes, transparent).catch((err) => {
|
|
5248
5098
|
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.`);
|
|
5249
5099
|
return null;
|
|
@@ -5545,7 +5395,7 @@ async function generateAndWriteHtml(inputPath, tempDir, config, cssAssets, image
|
|
|
5545
5395
|
...config,
|
|
5546
5396
|
printArea: config.page && { ...config.page, preset: config.preset, spec: config.spec }
|
|
5547
5397
|
}, {
|
|
5548
|
-
files: config.
|
|
5398
|
+
files: config.chapters ?? null,
|
|
5549
5399
|
onCssAssets: (copies) => {
|
|
5550
5400
|
for (const copy of copies)
|
|
5551
5401
|
nextAssets.set(copy.to, copy.from);
|
|
@@ -6501,32 +6351,41 @@ import { constants as FS, existsSync as existsSync7 } from "node:fs";
|
|
|
6501
6351
|
import path12 from "node:path";
|
|
6502
6352
|
|
|
6503
6353
|
// src/lib/page-size.ts
|
|
6504
|
-
import
|
|
6505
|
-
import { isMap, Scalar } from "yaml";
|
|
6354
|
+
import { isMap } from "yaml";
|
|
6506
6355
|
function writePageBounds(doc, page) {
|
|
6507
|
-
|
|
6508
|
-
if (!isMap(doc.get("page", true)))
|
|
6509
|
-
doc.set("page", doc.createNode({}));
|
|
6356
|
+
ensurePageMap(doc);
|
|
6510
6357
|
doc.setIn(["page", "width"], page.width);
|
|
6511
6358
|
doc.setIn(["page", "height"], page.height);
|
|
6512
|
-
|
|
6513
|
-
|
|
6359
|
+
doc.deleteIn(["page", "tolerance"]);
|
|
6360
|
+
}
|
|
6361
|
+
function deletePageBounds(doc) {
|
|
6362
|
+
const block = doc.get("page", true);
|
|
6363
|
+
if (!isMap(block)) {
|
|
6364
|
+
doc.delete("page");
|
|
6365
|
+
return;
|
|
6366
|
+
}
|
|
6367
|
+
for (const key of ["width", "height", "tolerance"])
|
|
6368
|
+
block.delete(key);
|
|
6369
|
+
if (block.items.length === 0)
|
|
6370
|
+
doc.delete("page");
|
|
6514
6371
|
}
|
|
6515
|
-
function
|
|
6516
|
-
|
|
6517
|
-
|
|
6372
|
+
function ensurePageMap(doc) {
|
|
6373
|
+
if (!isMap(doc.get("page", true)))
|
|
6374
|
+
doc.set("page", doc.createNode({}));
|
|
6518
6375
|
}
|
|
6519
6376
|
|
|
6520
6377
|
// src/lib/project-scaffold.ts
|
|
6521
6378
|
function starterOverridesCss() {
|
|
6522
6379
|
return `/**
|
|
6523
|
-
* Your book's own styles.
|
|
6380
|
+
* Your book's own styles. Rules here win over your look's.
|
|
6524
6381
|
*
|
|
6525
|
-
*
|
|
6526
|
-
*
|
|
6527
|
-
*
|
|
6528
|
-
*
|
|
6529
|
-
*
|
|
6382
|
+
* In the app you rarely need this file: Setup > Look chooses a look and
|
|
6383
|
+
* changes its fonts and colors (those changes are saved here as :root
|
|
6384
|
+
* custom properties), Setup > Advanced lists every setting, and Setup > Book
|
|
6385
|
+
* sets the page size and margins (in the manifest).
|
|
6386
|
+
*
|
|
6387
|
+
* To change the look from the command line: gutterpress ext remove <old>
|
|
6388
|
+
* <book>, then gutterpress ext add <look> <book>.
|
|
6530
6389
|
*/
|
|
6531
6390
|
`;
|
|
6532
6391
|
}
|
|
@@ -6562,9 +6421,6 @@ function requirePreset(preset, customPage) {
|
|
|
6562
6421
|
} else if (customPage && (!isPositivePoints(customPage.width) || !isPositivePoints(customPage.height))) {
|
|
6563
6422
|
throw new CreateProjectErrorImpl("custom-page-required", "Page overrides need a positive width and height in points (72pt = 1in).");
|
|
6564
6423
|
}
|
|
6565
|
-
if (customPage?.tolerance !== undefined && !isPositivePoints(customPage.tolerance)) {
|
|
6566
|
-
throw new CreateProjectErrorImpl("custom-page-required", "Page tolerance must be a positive number of points.");
|
|
6567
|
-
}
|
|
6568
6424
|
return preset;
|
|
6569
6425
|
}
|
|
6570
6426
|
function resolveScaffoldTargets(requested, preset) {
|
|
@@ -6649,6 +6505,8 @@ async function scaffoldProject(options) {
|
|
|
6649
6505
|
if (preset) {
|
|
6650
6506
|
doc.set("preset", preset);
|
|
6651
6507
|
doc.set("targets", doc.createNode(targets ?? []));
|
|
6508
|
+
if (preset !== "custom")
|
|
6509
|
+
deletePageBounds(doc);
|
|
6652
6510
|
}
|
|
6653
6511
|
if (options.customPage)
|
|
6654
6512
|
writePageBounds(doc, options.customPage);
|
|
@@ -6699,7 +6557,7 @@ async function firstSourceFile(manifestPath) {
|
|
|
6699
6557
|
} catch {
|
|
6700
6558
|
return;
|
|
6701
6559
|
}
|
|
6702
|
-
const filesIdx = text.search(
|
|
6560
|
+
const filesIdx = text.search(/^(?:chapters|\s+files):\s*$/m);
|
|
6703
6561
|
if (filesIdx === -1)
|
|
6704
6562
|
return;
|
|
6705
6563
|
const rest = text.slice(filesIdx);
|
|
@@ -9020,7 +8878,7 @@ async function resolvePublishProvider(id, book) {
|
|
|
9020
8878
|
const ext = await bookExtensions(book);
|
|
9021
8879
|
const npmEntry = ext.extensions.some((c) => !c.path && c.name === id);
|
|
9022
8880
|
if (npmEntry) {
|
|
9023
|
-
const { restoreForCommand: restoreForCommand2 } = await import("./extension-restore-
|
|
8881
|
+
const { restoreForCommand: restoreForCommand2 } = await import("./extension-restore-m8tj43e7.js");
|
|
9024
8882
|
await restoreForCommand2(book.projectDir, { manifestPath: book.manifestPath, failFast: true });
|
|
9025
8883
|
}
|
|
9026
8884
|
const publishers = await discover(ext);
|
|
@@ -9058,7 +8916,7 @@ function infoFor(p) {
|
|
|
9058
8916
|
}
|
|
9059
8917
|
function pluginProvider(p) {
|
|
9060
8918
|
let loading;
|
|
9061
|
-
const load = () => loading ??= import("./plugins-
|
|
8919
|
+
const load = () => loading ??= import("./plugins-sqa4msdk.js").then((m) => m.loadPublishFunction(p));
|
|
9062
8920
|
return {
|
|
9063
8921
|
info: infoFor(p),
|
|
9064
8922
|
async authenticate() {
|
|
@@ -9332,10 +9190,10 @@ async function disconnectPublishCredential(key, deps, options = {}) {
|
|
|
9332
9190
|
}
|
|
9333
9191
|
}
|
|
9334
9192
|
// src/lib/manifest-config.ts
|
|
9335
|
-
import { isSeq as isSeq2, isMap as isMap3, YAMLSeq, Scalar
|
|
9193
|
+
import { isSeq as isSeq2, isMap as isMap3, YAMLSeq, Scalar } from "yaml";
|
|
9336
9194
|
// src/lib/version-changes.ts
|
|
9337
9195
|
import git3 from "isomorphic-git";
|
|
9338
|
-
import
|
|
9196
|
+
import postcss5 from "postcss";
|
|
9339
9197
|
|
|
9340
9198
|
// src/lib/remote-auth/transport.ts
|
|
9341
9199
|
import git2 from "isomorphic-git";
|