gutterpress 0.11.20-alpha.2 → 0.11.20-alpha.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/index.js +3 -2
- package/dist/{build-qmjg9r2d.js → build-epdcrm2c.js} +5 -4
- package/dist/{cli-zacevwcy.js → cli-0ey902sx.js} +267 -455
- package/dist/{cli-j802s31j.js → cli-61vd4ews.js} +83 -41
- package/dist/{cli-7z29z4wz.js → cli-fmksazej.js} +1 -1
- package/dist/{cli-gh0ym80r.js → cli-h4tfmpg3.js} +121 -20
- package/dist/cli-sth219v1.js +418 -0
- package/dist/cli.js +12 -12
- package/dist/{doctor-fe7tcs4v.js → doctor-78es5scm.js} +2 -2
- package/dist/engine/compiler/build.d.ts +1 -1
- package/dist/engine/shared/margin-box-support.d.ts +2 -2
- package/dist/engine/shared/pin-edges.d.ts +127 -0
- package/dist/engine/shared/print-area.d.ts +68 -0
- package/dist/{engine-9xb1ky8d.js → engine-67f68bxs.js} +1 -1
- package/dist/{engine-yax79k9m.js → engine-7ha27n2b.js} +2 -2
- package/dist/{ext-ahwxt6gv.js → ext-9mc7sr0d.js} +5 -4
- package/dist/{gutterpress-agent-cazqstr1.js → gutterpress-agent-mrdnwktc.js} +78 -13
- package/dist/{gutterpress-viewer-retj6ym2.js → gutterpress-viewer-jr30yw8t.js} +155 -56
- package/dist/{index-6xwtb7cw.js → index-ad95fws8.js} +82 -40
- package/dist/{index-3nr5rzzp.js → index-gm5xbx5w.js} +3 -3
- package/dist/index-sth219v1.js +418 -0
- package/dist/{index-razpty47.js → index-t13p8y08.js} +493 -582
- package/dist/index.js +4 -3
- package/dist/lib/build-fingerprint.d.ts +8 -0
- package/dist/lib/extension-manifest.d.ts +13 -0
- package/dist/lib/ghostscript.d.ts +70 -16
- package/dist/lib/markdown/assemble.d.ts +12 -2
- package/dist/lib/markdown/gutterpress-css.d.ts +46 -30
- package/dist/lib/markdown/index.d.ts +5 -0
- package/dist/lib/pdf-inspect.d.ts +45 -0
- package/dist/{manifest.schema-74s1ykyv.json → manifest.schema-13dfax80.json} +16 -4
- package/dist/{new-ftd4fec4.js → new-s4f0tnya.js} +5 -4
- package/dist/pdf-inspect-zdmy7qca.js +35 -0
- package/dist/{preflight-8sqarcsr.js → preflight-7ck4rbsq.js} +5 -4
- package/dist/preview/file-watcher.d.ts +4 -10
- package/dist/{preview-q76xn95h.js → preview-j91sxadd.js} +5 -4
- package/dist/{publish-7gdy6gbf.js → publish-f12xaenm.js} +5 -4
- package/dist/render.js +57 -6
- package/dist/schema/manifest.types.d.ts +28 -8
- package/dist/test-helpers/testkit.d.ts +2 -2
- package/dist/{validate-e3ryegce.js → validate-pb5gysvr.js} +5 -4
- package/package.json +1 -1
- package/dist/engine/shared/flush.d.ts +0 -59
|
@@ -6,20 +6,22 @@ import {
|
|
|
6
6
|
defaultConfigDir,
|
|
7
7
|
error,
|
|
8
8
|
findPostScriptShadingPages,
|
|
9
|
-
|
|
9
|
+
flattenTransparentPages,
|
|
10
10
|
info,
|
|
11
11
|
log,
|
|
12
|
+
planTransparentPages,
|
|
12
13
|
resolveGhostscript,
|
|
13
14
|
setLogLevel,
|
|
14
15
|
stampCreator,
|
|
15
16
|
stripAnnotations,
|
|
17
|
+
transparentPages,
|
|
16
18
|
warn
|
|
17
|
-
} from "./cli-
|
|
19
|
+
} from "./cli-h4tfmpg3.js";
|
|
18
20
|
import {
|
|
19
21
|
DEBOUNCE,
|
|
20
22
|
UsageError,
|
|
21
23
|
resolvePort
|
|
22
|
-
} from "./cli-
|
|
24
|
+
} from "./cli-fmksazej.js";
|
|
23
25
|
import {
|
|
24
26
|
blackTextToGray
|
|
25
27
|
} from "./cli-ht1bcqdd.js";
|
|
@@ -28,11 +30,24 @@ import {
|
|
|
28
30
|
getAssetPath,
|
|
29
31
|
getAssetsDir,
|
|
30
32
|
lastPageMode
|
|
31
|
-
} from "./cli-
|
|
33
|
+
} from "./cli-61vd4ews.js";
|
|
32
34
|
import {
|
|
33
35
|
BuildError,
|
|
34
36
|
EXIT_CODES
|
|
35
37
|
} from "./cli-46ycxe6r.js";
|
|
38
|
+
import {
|
|
39
|
+
countLinkAnnotations,
|
|
40
|
+
getImageResolutions,
|
|
41
|
+
getOpPass,
|
|
42
|
+
getOutlineCount,
|
|
43
|
+
getPageLabels,
|
|
44
|
+
getPageSize,
|
|
45
|
+
getTextPass,
|
|
46
|
+
isLoadable,
|
|
47
|
+
loadPdf,
|
|
48
|
+
pageHasMarks,
|
|
49
|
+
retainPdfCache
|
|
50
|
+
} from "./cli-sth219v1.js";
|
|
36
51
|
import {
|
|
37
52
|
INSTALL_HINTS,
|
|
38
53
|
execCapture,
|
|
@@ -122,6 +137,8 @@ var DTRPG_PRESET = {
|
|
|
122
137
|
icc: "profiles/CGATS21_CRPC1.icc",
|
|
123
138
|
stripAnnotations: true,
|
|
124
139
|
blackText: "k-only",
|
|
140
|
+
transparency: "flatten-page",
|
|
141
|
+
flattenPages: [],
|
|
125
142
|
rasterDpi: undefined
|
|
126
143
|
},
|
|
127
144
|
page: {
|
|
@@ -207,6 +224,8 @@ var BOOK_PRESET = {
|
|
|
207
224
|
icc: "profiles/CGATS21_CRPC1.icc",
|
|
208
225
|
stripAnnotations: true,
|
|
209
226
|
blackText: "icc",
|
|
227
|
+
transparency: "flatten-page",
|
|
228
|
+
flattenPages: [],
|
|
210
229
|
rasterDpi: undefined
|
|
211
230
|
},
|
|
212
231
|
page: {
|
|
@@ -606,6 +625,14 @@ function resolveWithPreset(cliOverrides, manifest, preset) {
|
|
|
606
625
|
if (lastPage !== undefined && lastPage !== "blank" && lastPage !== "short-by-one") {
|
|
607
626
|
throw new UsageError(`Manifest field \`print.lastPage\` must be "blank" or "short-by-one", got ${JSON.stringify(lastPage)}.`);
|
|
608
627
|
}
|
|
628
|
+
const transparency = c.pdfx?.transparency ?? m.pdfx?.transparency;
|
|
629
|
+
if (transparency !== undefined && transparency !== "flatten-page" && transparency !== "preserve-text") {
|
|
630
|
+
throw new UsageError(`Manifest field \`pdfx.transparency\` must be "flatten-page" or "preserve-text", got ${JSON.stringify(transparency)}.`);
|
|
631
|
+
}
|
|
632
|
+
const flattenPages = c.pdfx?.flattenPages ?? m.pdfx?.flattenPages;
|
|
633
|
+
if (flattenPages !== undefined && !(Array.isArray(flattenPages) && flattenPages.every((n) => Number.isInteger(n) && n >= 1))) {
|
|
634
|
+
throw new UsageError(`Manifest field \`pdfx.flattenPages\` must be a list of page numbers (1, 2, …), got ${JSON.stringify(flattenPages)}.`);
|
|
635
|
+
}
|
|
609
636
|
const rasterDpi = c.pdfx?.rasterDpi ?? m.pdfx?.rasterDpi;
|
|
610
637
|
if (rasterDpi !== undefined && !(Number.isInteger(rasterDpi) && rasterDpi >= 72 && rasterDpi <= 1200)) {
|
|
611
638
|
throw new UsageError(`Manifest field \`pdfx.rasterDpi\` must be a whole number from 72 to 1200, got ${JSON.stringify(rasterDpi)}.`);
|
|
@@ -674,6 +701,7 @@ function resolveDeclaredStyles(rawStyles, baseDir, subject) {
|
|
|
674
701
|
// src/lib/extension-manifest.ts
|
|
675
702
|
import { readFile as readFile2 } from "node:fs/promises";
|
|
676
703
|
import path from "node:path";
|
|
704
|
+
import { satisfies, validRange } from "semver";
|
|
677
705
|
var EXTENSION_MANIFEST_FILENAME = "package.json";
|
|
678
706
|
var GUTTERPRESS_KEY = "gutterpress";
|
|
679
707
|
function object(value) {
|
|
@@ -697,6 +725,7 @@ function metaFromPackageJson(raw) {
|
|
|
697
725
|
...str(pkg.description) ? { description: str(pkg.description) } : {},
|
|
698
726
|
...keywords ? { keywords } : {},
|
|
699
727
|
...str(pkg.main) ? { main: str(pkg.main) } : {},
|
|
728
|
+
...str(object(pkg.engines)?.gutterpress) ? { gutterpressRange: str(object(pkg.engines)?.gutterpress) } : {},
|
|
700
729
|
..."preview" in gp ? { preview: str(gp.preview) ?? null } : {},
|
|
701
730
|
...Array.isArray(gp.styles) ? { styles: declaredList(gp.styles) } : {},
|
|
702
731
|
...str(gp.tokensFile) ? { tokensFile: str(gp.tokensFile) } : {},
|
|
@@ -733,6 +762,17 @@ function extensionCarries(meta) {
|
|
|
733
762
|
function pathEscapesFolder(rel) {
|
|
734
763
|
return path.isAbsolute(rel) || rel.split(/[\\/]/).includes("..");
|
|
735
764
|
}
|
|
765
|
+
function assertSupportsThisGutterpress(meta, ref) {
|
|
766
|
+
const range = meta.gutterpressRange;
|
|
767
|
+
if (range === undefined)
|
|
768
|
+
return;
|
|
769
|
+
if (!validRange(range)) {
|
|
770
|
+
throw new Error(`Extension "${ref}" has an invalid engines.gutterpress range "${range}".`);
|
|
771
|
+
}
|
|
772
|
+
if (!satisfies(PACKAGE_VERSION, range, { includePrerelease: true })) {
|
|
773
|
+
throw new Error(`Extension "${ref}" needs Gutterpress ${range} (its package.json engines.gutterpress); ` + `this is Gutterpress ${PACKAGE_VERSION}. Update Gutterpress, or pin an older version of the extension.`);
|
|
774
|
+
}
|
|
775
|
+
}
|
|
736
776
|
function assertExtensionContained(meta) {
|
|
737
777
|
if (meta.engineStyles !== undefined) {
|
|
738
778
|
throw new Error("The extension's metadata declares `engineStyles`, which was removed — " + "move its entries to the end of `styles`.");
|
|
@@ -2004,7 +2044,9 @@ var GUTTERPRESS_CSS = `
|
|
|
2004
2044
|
cap at equal specificity */
|
|
2005
2045
|
.gp-small { width: 25%; max-width: 100%; }
|
|
2006
2046
|
.gp-medium { width: 50%; max-width: 100%; }
|
|
2007
|
-
.gp-large { width:
|
|
2047
|
+
.gp-large { width: 60%; max-width: 100%; }
|
|
2048
|
+
.gp-xl { width: 80%; max-width: 100%; }
|
|
2049
|
+
.gp-xxl { width: 90%; max-width: 100%; }
|
|
2008
2050
|
|
|
2009
2051
|
/* float clearance presets — consumed by var(--gp-gap) in the float rules
|
|
2010
2052
|
above and by .gp-shape's shape-margin below; --gp-gap itself is
|
|
@@ -2062,10 +2104,16 @@ img.gp-shape {
|
|
|
2062
2104
|
}
|
|
2063
2105
|
|
|
2064
2106
|
/* pin — within the nearest positioned ancestor (.page/.spread, rule above).
|
|
2065
|
-
|
|
2107
|
+
The four insets are the pin box: 0 (the text block's edge) unless an
|
|
2108
|
+
engine set --gp-pin-<edge> on the page root for an edge a pin uses (the
|
|
2109
|
+
art-safe line). Non-auto insets and the explicit centers are
|
|
2110
|
+
load-bearing; see doctrine comment. */
|
|
2066
2111
|
.gp-pin {
|
|
2067
2112
|
position: absolute;
|
|
2068
|
-
|
|
2113
|
+
top: var(--gp-pin-top, 0px);
|
|
2114
|
+
right: var(--gp-pin-right, 0px);
|
|
2115
|
+
bottom: var(--gp-pin-bottom, 0px);
|
|
2116
|
+
left: var(--gp-pin-left, 0px);
|
|
2069
2117
|
align-self: center;
|
|
2070
2118
|
justify-self: center;
|
|
2071
2119
|
margin: 0;
|
|
@@ -2080,6 +2128,16 @@ img.gp-shape {
|
|
|
2080
2128
|
.gp-left { justify-self: start; }
|
|
2081
2129
|
.gp-right { justify-self: end; }
|
|
2082
2130
|
|
|
2131
|
+
/* the escape hatch — the paper's edge, past the printer's safe area: the
|
|
2132
|
+
pin box loses its art-safe insets. Set on the pin itself, so it beats the
|
|
2133
|
+
values the page root hands down. */
|
|
2134
|
+
.gp-pin.gp-flush {
|
|
2135
|
+
--gp-pin-top: 0px;
|
|
2136
|
+
--gp-pin-right: 0px;
|
|
2137
|
+
--gp-pin-bottom: 0px;
|
|
2138
|
+
--gp-pin-left: 0px;
|
|
2139
|
+
}
|
|
2140
|
+
|
|
2083
2141
|
/* wrapper-margin neutralization (same pattern and rationale as the
|
|
2084
2142
|
.gp-bleed paragraph-margin note in the doctrine comment; for pin, the
|
|
2085
2143
|
emptied paragraph would otherwise leave a phantom margin gap in flow) */
|
|
@@ -2189,6 +2247,8 @@ var GP_CLASSES = new Set([
|
|
|
2189
2247
|
"gp-small",
|
|
2190
2248
|
"gp-medium",
|
|
2191
2249
|
"gp-large",
|
|
2250
|
+
"gp-xl",
|
|
2251
|
+
"gp-xxl",
|
|
2192
2252
|
"gp-tight",
|
|
2193
2253
|
"gp-loose",
|
|
2194
2254
|
"gp-columns",
|
|
@@ -2205,6 +2265,7 @@ var GP_CLASSES = new Set([
|
|
|
2205
2265
|
"gp-pin",
|
|
2206
2266
|
"gp-top",
|
|
2207
2267
|
"gp-bottom",
|
|
2268
|
+
"gp-flush",
|
|
2208
2269
|
"gp-behind",
|
|
2209
2270
|
"gp-base",
|
|
2210
2271
|
"gp-raised",
|
|
@@ -2218,8 +2279,7 @@ var GP_CLASSES = new Set([
|
|
|
2218
2279
|
"gp-alert-caution",
|
|
2219
2280
|
"gp-page-break",
|
|
2220
2281
|
"gp-column-break",
|
|
2221
|
-
"gp-continued"
|
|
2222
|
-
"gp-flush"
|
|
2282
|
+
"gp-continued"
|
|
2223
2283
|
]);
|
|
2224
2284
|
|
|
2225
2285
|
// src/lib/markdown/gp-pin-scope.js
|
|
@@ -2256,6 +2316,21 @@ function hasPinClass(token) {
|
|
|
2256
2316
|
const cls = token.attrGet && token.attrGet("class");
|
|
2257
2317
|
return typeof cls === "string" && cls.split(/\s+/).includes("gp-pin");
|
|
2258
2318
|
}
|
|
2319
|
+
var PIN_EDGES = ["gp-top", "gp-right", "gp-bottom", "gp-left"];
|
|
2320
|
+
var FLUSH_ART_MSG = "`.gp-flush` puts this image on the paper's edge, past the printer's safe area. Printers trim up to 0.125in there, so keep it for art that is meant to bleed off the page.";
|
|
2321
|
+
function checkFlushArt(token, env, line) {
|
|
2322
|
+
if (token.type !== "image")
|
|
2323
|
+
return;
|
|
2324
|
+
const cls = token.attrGet && token.attrGet("class");
|
|
2325
|
+
if (typeof cls !== "string")
|
|
2326
|
+
return;
|
|
2327
|
+
const classes = cls.split(/\s+/);
|
|
2328
|
+
if (!classes.includes("gp-pin") || !classes.includes("gp-flush"))
|
|
2329
|
+
return;
|
|
2330
|
+
if (!classes.some((c) => PIN_EDGES.includes(c)))
|
|
2331
|
+
return;
|
|
2332
|
+
warn3(env, line, "flush_art", FLUSH_ART_MSG);
|
|
2333
|
+
}
|
|
2259
2334
|
function elementNameFor(token) {
|
|
2260
2335
|
switch (token.type) {
|
|
2261
2336
|
case "layout_chapter_open":
|
|
@@ -2315,6 +2390,7 @@ function gpPinScope(md) {
|
|
|
2315
2390
|
if (token.type === "inline" && token.children) {
|
|
2316
2391
|
for (const child of token.children) {
|
|
2317
2392
|
checkUnknownGpClasses(child, state.env, line);
|
|
2393
|
+
checkFlushArt(child, state.env, line);
|
|
2318
2394
|
}
|
|
2319
2395
|
}
|
|
2320
2396
|
}
|
|
@@ -3342,6 +3418,7 @@ This folder still has a ${stale}. Gutterpress no longer reads it — ` + `descri
|
|
|
3342
3418
|
async function loadExtensionFromDir(extensionDir, config, pluginRef) {
|
|
3343
3419
|
const meta = await readExtensionMeta(extensionDir);
|
|
3344
3420
|
assertExtensionContained(meta);
|
|
3421
|
+
assertSupportsThisGutterpress(meta, pluginRef);
|
|
3345
3422
|
const resolved = resolveExtension(extensionDir, meta, `Plugin "${pluginRef}"`);
|
|
3346
3423
|
const extensionStyles = resolved.styles ?? [];
|
|
3347
3424
|
const name = config.name ?? meta.name ?? pluginRef;
|
|
@@ -3416,6 +3493,7 @@ async function loadPlugin(config, baseDir) {
|
|
|
3416
3493
|
if (loaded.packageDir) {
|
|
3417
3494
|
const meta = await readExtensionMeta(loaded.packageDir);
|
|
3418
3495
|
assertExtensionContained(meta);
|
|
3496
|
+
assertSupportsThisGutterpress(meta, pluginRef);
|
|
3419
3497
|
const resolved = resolveExtension(loaded.packageDir, { ...meta, main: undefined }, `Plugin "${pluginRef}"`);
|
|
3420
3498
|
if (resolved.markdown && loaded.entryPath && resolve3(resolved.markdown) !== resolve3(loaded.entryPath)) {
|
|
3421
3499
|
throw new Error(`its package.json declares gutterpress.markdown "${meta.markdown}" but the package entry is "${relative(loaded.packageDir, loaded.entryPath)}" — an npm extension's ` + "markdown-it plugin is its package entry, so declare that file or drop the field.");
|
|
@@ -3539,7 +3617,7 @@ import path3 from "node:path";
|
|
|
3539
3617
|
import { Transform } from "node:stream";
|
|
3540
3618
|
import { pipeline } from "node:stream/promises";
|
|
3541
3619
|
import { createGunzip } from "node:zlib";
|
|
3542
|
-
import { maxSatisfying, satisfies, validRange } from "semver";
|
|
3620
|
+
import { maxSatisfying, satisfies as satisfies2, validRange as validRange2 } from "semver";
|
|
3543
3621
|
|
|
3544
3622
|
// src/lib/fetch-timeout.ts
|
|
3545
3623
|
class FetchPassthroughError extends Error {
|
|
@@ -3780,7 +3858,7 @@ async function selectPackage(ctx, name, selector) {
|
|
|
3780
3858
|
version = selector;
|
|
3781
3859
|
} else if (typeof tags[selector] === "string") {
|
|
3782
3860
|
version = tags[selector];
|
|
3783
|
-
} else if (
|
|
3861
|
+
} else if (validRange2(selector)) {
|
|
3784
3862
|
version = maxSatisfying(Object.keys(versions), selector) ?? undefined;
|
|
3785
3863
|
}
|
|
3786
3864
|
if (!version || !isExactNpmVersion(version)) {
|
|
@@ -3998,7 +4076,7 @@ async function installPackage(ctx, name, selector, parentPackagePath, ancestors,
|
|
|
3998
4076
|
}
|
|
3999
4077
|
throw error2;
|
|
4000
4078
|
}
|
|
4001
|
-
const ancestor = ancestors.find((candidate) => candidate.name === name && (candidate.version === selected.version || (selector ?
|
|
4079
|
+
const ancestor = ancestors.find((candidate) => candidate.name === name && (candidate.version === selected.version || (selector ? satisfies2(candidate.version, selector) : false)));
|
|
4002
4080
|
if (ancestor)
|
|
4003
4081
|
return { path: ancestor.path };
|
|
4004
4082
|
if (ctx.records.length >= ctx.limits.totalPackages) {
|
|
@@ -4899,346 +4977,6 @@ function inspectionFailed(checkId, message, extra = {}) {
|
|
|
4899
4977
|
};
|
|
4900
4978
|
}
|
|
4901
4979
|
|
|
4902
|
-
// src/lib/pdf-inspect.ts
|
|
4903
|
-
import { stat as stat2, readFile as readFile7 } from "node:fs/promises";
|
|
4904
|
-
import { getDocumentProxy } from "unpdf";
|
|
4905
|
-
import * as pdfjs from "unpdf/pdfjs";
|
|
4906
|
-
function getOps(mod) {
|
|
4907
|
-
if ("OPS" in mod && mod.OPS && typeof mod.OPS === "object") {
|
|
4908
|
-
return mod.OPS;
|
|
4909
|
-
}
|
|
4910
|
-
throw new Error("unpdf/pdfjs missing OPS export");
|
|
4911
|
-
}
|
|
4912
|
-
var OPS = getOps(pdfjs);
|
|
4913
|
-
var docCache = new Map;
|
|
4914
|
-
var DOC_CACHE_MAX = 8;
|
|
4915
|
-
function destroyEntry(entry) {
|
|
4916
|
-
entry.doc.then((d) => d.destroy()).catch(() => {});
|
|
4917
|
-
}
|
|
4918
|
-
var EVICT_DESTROY_GRACE_MS = 60000;
|
|
4919
|
-
var gracePending = new Map;
|
|
4920
|
-
function destroyEntryAfterGrace(entry) {
|
|
4921
|
-
const t = setTimeout(() => {
|
|
4922
|
-
gracePending.delete(t);
|
|
4923
|
-
destroyEntry(entry);
|
|
4924
|
-
}, EVICT_DESTROY_GRACE_MS);
|
|
4925
|
-
t.unref?.();
|
|
4926
|
-
gracePending.set(t, entry);
|
|
4927
|
-
}
|
|
4928
|
-
function evictLru() {
|
|
4929
|
-
while (docCache.size > DOC_CACHE_MAX) {
|
|
4930
|
-
const oldestKey = docCache.keys().next().value;
|
|
4931
|
-
if (oldestKey === undefined)
|
|
4932
|
-
break;
|
|
4933
|
-
const evicted = docCache.get(oldestKey);
|
|
4934
|
-
docCache.delete(oldestKey);
|
|
4935
|
-
if (evicted)
|
|
4936
|
-
destroyEntryAfterGrace(evicted);
|
|
4937
|
-
}
|
|
4938
|
-
}
|
|
4939
|
-
async function loadPdf(path6) {
|
|
4940
|
-
let st;
|
|
4941
|
-
try {
|
|
4942
|
-
st = await stat2(path6);
|
|
4943
|
-
} catch {
|
|
4944
|
-
return null;
|
|
4945
|
-
}
|
|
4946
|
-
const hit = docCache.get(path6);
|
|
4947
|
-
if (hit && hit.mtimeMs === st.mtimeMs && hit.size === st.size) {
|
|
4948
|
-
docCache.delete(path6);
|
|
4949
|
-
docCache.set(path6, hit);
|
|
4950
|
-
try {
|
|
4951
|
-
return await hit.doc;
|
|
4952
|
-
} catch {
|
|
4953
|
-
return null;
|
|
4954
|
-
}
|
|
4955
|
-
}
|
|
4956
|
-
if (hit)
|
|
4957
|
-
destroyEntry(hit);
|
|
4958
|
-
const docPromise = readFile7(path6).then((buf) => getDocumentProxy(new Uint8Array(buf)));
|
|
4959
|
-
docCache.delete(path6);
|
|
4960
|
-
docCache.set(path6, { mtimeMs: st.mtimeMs, size: st.size, doc: docPromise });
|
|
4961
|
-
evictLru();
|
|
4962
|
-
try {
|
|
4963
|
-
return await docPromise;
|
|
4964
|
-
} catch {
|
|
4965
|
-
if (docCache.get(path6)?.doc === docPromise)
|
|
4966
|
-
docCache.delete(path6);
|
|
4967
|
-
return null;
|
|
4968
|
-
}
|
|
4969
|
-
}
|
|
4970
|
-
var activeRetains = 0;
|
|
4971
|
-
function retainPdfCache() {
|
|
4972
|
-
activeRetains++;
|
|
4973
|
-
let released = false;
|
|
4974
|
-
return () => {
|
|
4975
|
-
if (released)
|
|
4976
|
-
return;
|
|
4977
|
-
released = true;
|
|
4978
|
-
activeRetains--;
|
|
4979
|
-
if (activeRetains === 0)
|
|
4980
|
-
clearPdfCache();
|
|
4981
|
-
};
|
|
4982
|
-
}
|
|
4983
|
-
function clearPdfCache() {
|
|
4984
|
-
for (const [t, entry] of gracePending) {
|
|
4985
|
-
clearTimeout(t);
|
|
4986
|
-
destroyEntry(entry);
|
|
4987
|
-
}
|
|
4988
|
-
gracePending.clear();
|
|
4989
|
-
for (const entry of docCache.values())
|
|
4990
|
-
destroyEntry(entry);
|
|
4991
|
-
docCache.clear();
|
|
4992
|
-
}
|
|
4993
|
-
function getPageSize(page) {
|
|
4994
|
-
const vp = page.getViewport({ scale: 1 });
|
|
4995
|
-
return { w: vp.width, h: vp.height };
|
|
4996
|
-
}
|
|
4997
|
-
async function getOutlineCount(doc) {
|
|
4998
|
-
try {
|
|
4999
|
-
const outline = await doc.getOutline();
|
|
5000
|
-
return outline ? outline.length : 0;
|
|
5001
|
-
} catch {
|
|
5002
|
-
return 0;
|
|
5003
|
-
}
|
|
5004
|
-
}
|
|
5005
|
-
async function getPageLabels(doc) {
|
|
5006
|
-
try {
|
|
5007
|
-
return await doc.getPageLabels();
|
|
5008
|
-
} catch {
|
|
5009
|
-
return null;
|
|
5010
|
-
}
|
|
5011
|
-
}
|
|
5012
|
-
async function countLinkAnnotations(doc, stopAtFirst = false) {
|
|
5013
|
-
let count = 0;
|
|
5014
|
-
for (let i = 1;i <= doc.numPages; i++) {
|
|
5015
|
-
try {
|
|
5016
|
-
const page = await doc.getPage(i);
|
|
5017
|
-
const annots = await page.getAnnotations();
|
|
5018
|
-
for (const a of annots) {
|
|
5019
|
-
if (a.subtype === "Link") {
|
|
5020
|
-
count++;
|
|
5021
|
-
if (stopAtFirst)
|
|
5022
|
-
return count;
|
|
5023
|
-
}
|
|
5024
|
-
}
|
|
5025
|
-
} catch {}
|
|
5026
|
-
}
|
|
5027
|
-
return count;
|
|
5028
|
-
}
|
|
5029
|
-
var textCache = new WeakMap;
|
|
5030
|
-
function getTextPass(doc) {
|
|
5031
|
-
let p = textCache.get(doc);
|
|
5032
|
-
if (!p) {
|
|
5033
|
-
p = (async () => {
|
|
5034
|
-
const textByPage = [];
|
|
5035
|
-
const positions = [];
|
|
5036
|
-
const runsByPage = [];
|
|
5037
|
-
for (let i = 1;i <= doc.numPages; i++) {
|
|
5038
|
-
try {
|
|
5039
|
-
const page = await doc.getPage(i);
|
|
5040
|
-
const tc = await page.getTextContent();
|
|
5041
|
-
let pageText = "";
|
|
5042
|
-
const runs = [];
|
|
5043
|
-
for (const item of tc.items) {
|
|
5044
|
-
const it = item;
|
|
5045
|
-
if (typeof it.str !== "string")
|
|
5046
|
-
continue;
|
|
5047
|
-
pageText += it.str;
|
|
5048
|
-
if (it.transform && it.str.trim().length > 0) {
|
|
5049
|
-
const x = it.transform[4];
|
|
5050
|
-
const y = it.transform[5];
|
|
5051
|
-
positions.push({ x, y });
|
|
5052
|
-
runs.push({ s: it.str, x, y, w: it.width ?? 0, h: it.height ?? 0 });
|
|
5053
|
-
}
|
|
5054
|
-
}
|
|
5055
|
-
textByPage.push(pageText);
|
|
5056
|
-
runsByPage.push(runs);
|
|
5057
|
-
} catch {
|
|
5058
|
-
textByPage.push("");
|
|
5059
|
-
runsByPage.push([]);
|
|
5060
|
-
}
|
|
5061
|
-
}
|
|
5062
|
-
return { textByPage, positions, runsByPage };
|
|
5063
|
-
})();
|
|
5064
|
-
textCache.set(doc, p);
|
|
5065
|
-
}
|
|
5066
|
-
return p;
|
|
5067
|
-
}
|
|
5068
|
-
var opCache = new WeakMap;
|
|
5069
|
-
function multiply(m1, m2) {
|
|
5070
|
-
return [
|
|
5071
|
-
m1[0] * m2[0] + m1[2] * m2[1],
|
|
5072
|
-
m1[1] * m2[0] + m1[3] * m2[1],
|
|
5073
|
-
m1[0] * m2[2] + m1[2] * m2[3],
|
|
5074
|
-
m1[1] * m2[2] + m1[3] * m2[3],
|
|
5075
|
-
m1[0] * m2[4] + m1[2] * m2[5] + m1[4],
|
|
5076
|
-
m1[1] * m2[4] + m1[3] * m2[5] + m1[5]
|
|
5077
|
-
];
|
|
5078
|
-
}
|
|
5079
|
-
function fontIsEmbedded(f) {
|
|
5080
|
-
if (f.isType3Font)
|
|
5081
|
-
return true;
|
|
5082
|
-
if (f.missingFile === true)
|
|
5083
|
-
return false;
|
|
5084
|
-
if (f.isStandardFont === true)
|
|
5085
|
-
return false;
|
|
5086
|
-
return true;
|
|
5087
|
-
}
|
|
5088
|
-
function getOpPass(doc) {
|
|
5089
|
-
let p = opCache.get(doc);
|
|
5090
|
-
if (!p) {
|
|
5091
|
-
p = (async () => {
|
|
5092
|
-
const imagesByPage = new Map;
|
|
5093
|
-
const fonts = [];
|
|
5094
|
-
const seenFonts = new Set;
|
|
5095
|
-
for (let i = 1;i <= doc.numPages; i++) {
|
|
5096
|
-
let page;
|
|
5097
|
-
try {
|
|
5098
|
-
page = await doc.getPage(i);
|
|
5099
|
-
} catch {
|
|
5100
|
-
continue;
|
|
5101
|
-
}
|
|
5102
|
-
let ops;
|
|
5103
|
-
try {
|
|
5104
|
-
ops = await page.getOperatorList();
|
|
5105
|
-
} catch {
|
|
5106
|
-
continue;
|
|
5107
|
-
}
|
|
5108
|
-
let ctm = [1, 0, 0, 1, 0, 0];
|
|
5109
|
-
const stack = [];
|
|
5110
|
-
const pageImages = [];
|
|
5111
|
-
for (let j = 0;j < ops.fnArray.length; j++) {
|
|
5112
|
-
const fn = ops.fnArray[j];
|
|
5113
|
-
const args = ops.argsArray[j];
|
|
5114
|
-
if (fn === OPS.save) {
|
|
5115
|
-
stack.push(ctm.slice());
|
|
5116
|
-
} else if (fn === OPS.restore) {
|
|
5117
|
-
ctm = stack.pop() ?? ctm;
|
|
5118
|
-
} else if (fn === OPS.transform) {
|
|
5119
|
-
ctm = multiply(ctm, args);
|
|
5120
|
-
} else if (fn === OPS.paintImageXObject || fn === OPS.paintImageXObjectRepeat || fn === OPS.paintInlineImageXObject) {
|
|
5121
|
-
const name = typeof args[0] === "string" ? args[0] : "(inline)";
|
|
5122
|
-
pageImages.push({
|
|
5123
|
-
name,
|
|
5124
|
-
placedW: Math.hypot(ctm[0], ctm[1]),
|
|
5125
|
-
placedH: Math.hypot(ctm[2], ctm[3]),
|
|
5126
|
-
x: ctm[4],
|
|
5127
|
-
y: ctm[5],
|
|
5128
|
-
page: i
|
|
5129
|
-
});
|
|
5130
|
-
} else if (fn === OPS.setFont) {
|
|
5131
|
-
const ref = args[0];
|
|
5132
|
-
if (typeof ref === "string" && !seenFonts.has(ref)) {
|
|
5133
|
-
seenFonts.add(ref);
|
|
5134
|
-
try {
|
|
5135
|
-
if (page.commonObjs.has(ref)) {
|
|
5136
|
-
const f = page.commonObjs.get(ref);
|
|
5137
|
-
fonts.push({
|
|
5138
|
-
name: f?.name ?? ref,
|
|
5139
|
-
embedded: fontIsEmbedded(f ?? {})
|
|
5140
|
-
});
|
|
5141
|
-
}
|
|
5142
|
-
} catch {}
|
|
5143
|
-
}
|
|
5144
|
-
}
|
|
5145
|
-
}
|
|
5146
|
-
if (pageImages.length > 0)
|
|
5147
|
-
imagesByPage.set(i, pageImages);
|
|
5148
|
-
}
|
|
5149
|
-
return { imagesByPage, fonts };
|
|
5150
|
-
})();
|
|
5151
|
-
opCache.set(doc, p);
|
|
5152
|
-
}
|
|
5153
|
-
return p;
|
|
5154
|
-
}
|
|
5155
|
-
function getImagePixelSize(page, name, timeoutMs = 2000) {
|
|
5156
|
-
return new Promise((resolve4) => {
|
|
5157
|
-
let done = false;
|
|
5158
|
-
const finish = (v) => {
|
|
5159
|
-
if (!done) {
|
|
5160
|
-
done = true;
|
|
5161
|
-
resolve4(v);
|
|
5162
|
-
}
|
|
5163
|
-
};
|
|
5164
|
-
const t = setTimeout(() => finish(null), timeoutMs);
|
|
5165
|
-
try {
|
|
5166
|
-
page.objs.get(name, (obj) => {
|
|
5167
|
-
clearTimeout(t);
|
|
5168
|
-
finish(obj && obj.width && obj.height ? { width: obj.width, height: obj.height } : null);
|
|
5169
|
-
});
|
|
5170
|
-
} catch {
|
|
5171
|
-
clearTimeout(t);
|
|
5172
|
-
finish(null);
|
|
5173
|
-
}
|
|
5174
|
-
});
|
|
5175
|
-
}
|
|
5176
|
-
var PAINT_OPS = new Set([
|
|
5177
|
-
"stroke",
|
|
5178
|
-
"closeStroke",
|
|
5179
|
-
"fill",
|
|
5180
|
-
"eoFill",
|
|
5181
|
-
"fillStroke",
|
|
5182
|
-
"eoFillStroke",
|
|
5183
|
-
"closeFillStroke",
|
|
5184
|
-
"closeEOFillStroke",
|
|
5185
|
-
"shadingFill",
|
|
5186
|
-
"paintImageXObject",
|
|
5187
|
-
"paintInlineImageXObject",
|
|
5188
|
-
"paintImageXObjectRepeat",
|
|
5189
|
-
"paintImageMaskXObject",
|
|
5190
|
-
"paintImageMaskXObjectGroup",
|
|
5191
|
-
"paintImageMaskXObjectRepeat",
|
|
5192
|
-
"paintSolidColorImageMask",
|
|
5193
|
-
"showText",
|
|
5194
|
-
"showSpacedText",
|
|
5195
|
-
"nextLineShowText",
|
|
5196
|
-
"nextLineSetSpacingShowText"
|
|
5197
|
-
].map((name) => OPS[name]).filter((op) => op !== undefined));
|
|
5198
|
-
async function pageHasMarks(doc, pageNum) {
|
|
5199
|
-
const ops = await (await doc.getPage(pageNum)).getOperatorList();
|
|
5200
|
-
return ops.fnArray.some((fn, i) => fn === OPS.constructPath ? PAINT_OPS.has(ops.argsArray[i][0]) : PAINT_OPS.has(fn));
|
|
5201
|
-
}
|
|
5202
|
-
async function getImageResolutions(doc) {
|
|
5203
|
-
const { imagesByPage } = await getOpPass(doc);
|
|
5204
|
-
const out = [];
|
|
5205
|
-
for (const [pageNum, imgs] of imagesByPage) {
|
|
5206
|
-
let page;
|
|
5207
|
-
try {
|
|
5208
|
-
page = await doc.getPage(pageNum);
|
|
5209
|
-
} catch {
|
|
5210
|
-
continue;
|
|
5211
|
-
}
|
|
5212
|
-
for (const img of imgs) {
|
|
5213
|
-
if (img.name === "(inline)")
|
|
5214
|
-
continue;
|
|
5215
|
-
const px = await getImagePixelSize(page, img.name);
|
|
5216
|
-
if (!px)
|
|
5217
|
-
continue;
|
|
5218
|
-
const placedWin = img.placedW / 72;
|
|
5219
|
-
const placedHin = img.placedH / 72;
|
|
5220
|
-
if (placedWin <= 0 || placedHin <= 0)
|
|
5221
|
-
continue;
|
|
5222
|
-
out.push({
|
|
5223
|
-
page: pageNum,
|
|
5224
|
-
xDpi: px.width / placedWin,
|
|
5225
|
-
yDpi: px.height / placedHin
|
|
5226
|
-
});
|
|
5227
|
-
}
|
|
5228
|
-
}
|
|
5229
|
-
return out;
|
|
5230
|
-
}
|
|
5231
|
-
async function isLoadable(doc) {
|
|
5232
|
-
try {
|
|
5233
|
-
for (let i = 1;i <= doc.numPages; i++) {
|
|
5234
|
-
await doc.getPage(i);
|
|
5235
|
-
}
|
|
5236
|
-
return true;
|
|
5237
|
-
} catch {
|
|
5238
|
-
return false;
|
|
5239
|
-
}
|
|
5240
|
-
}
|
|
5241
|
-
|
|
5242
4980
|
// src/checks/pdf/qpdf-structure.ts
|
|
5243
4981
|
var check = {
|
|
5244
4982
|
id: "pdf.structure.qpdf",
|
|
@@ -5513,9 +5251,9 @@ var check4 = {
|
|
|
5513
5251
|
registerCheck(check4);
|
|
5514
5252
|
|
|
5515
5253
|
// src/lib/pdf-parse.ts
|
|
5516
|
-
import { readFile as
|
|
5254
|
+
import { readFile as readFile7 } from "node:fs/promises";
|
|
5517
5255
|
async function readPdfBytes(pdfPath) {
|
|
5518
|
-
return
|
|
5256
|
+
return readFile7(pdfPath, "latin1");
|
|
5519
5257
|
}
|
|
5520
5258
|
function parseInkCov(out) {
|
|
5521
5259
|
const lines = out.split(/\r?\n/).filter((l) => l.includes("CMYK"));
|
|
@@ -5776,7 +5514,7 @@ var check8 = {
|
|
|
5776
5514
|
registerCheck(check8);
|
|
5777
5515
|
|
|
5778
5516
|
// src/checks/pdf/black-text.ts
|
|
5779
|
-
import { readFile as
|
|
5517
|
+
import { readFile as readFile8 } from "node:fs/promises";
|
|
5780
5518
|
var check9 = {
|
|
5781
5519
|
id: "pdf.print.black-text",
|
|
5782
5520
|
name: "Black Text",
|
|
@@ -5789,7 +5527,7 @@ var check9 = {
|
|
|
5789
5527
|
return [];
|
|
5790
5528
|
try {
|
|
5791
5529
|
const { findRichBlackText, LARGE_TEXT_PT } = await import("./black-text-gray-7dz61456.js");
|
|
5792
|
-
const found = await findRichBlackText(await
|
|
5530
|
+
const found = await findRichBlackText(await readFile8(ctx.pdfPath));
|
|
5793
5531
|
if (found.runs === 0)
|
|
5794
5532
|
return [];
|
|
5795
5533
|
return [
|
|
@@ -6178,7 +5916,7 @@ var check18 = {
|
|
|
6178
5916
|
registerCheck(check18);
|
|
6179
5917
|
|
|
6180
5918
|
// src/checks/source/markdownlint.ts
|
|
6181
|
-
import { readFile as
|
|
5919
|
+
import { readFile as readFile9 } from "node:fs/promises";
|
|
6182
5920
|
import { lint } from "markdownlint/sync";
|
|
6183
5921
|
import { parse as parseYaml2 } from "yaml";
|
|
6184
5922
|
|
|
@@ -6211,7 +5949,7 @@ function stripJsonComments(s) {
|
|
|
6211
5949
|
return s.replace(/\/\*[\s\S]*?\*\//g, "").replace(/(^|[^:])\/\/.*$/gm, "$1");
|
|
6212
5950
|
}
|
|
6213
5951
|
async function loadConfig(configPath) {
|
|
6214
|
-
const raw = await
|
|
5952
|
+
const raw = await readFile9(configPath, "utf8");
|
|
6215
5953
|
let parsed;
|
|
6216
5954
|
if (configPath.endsWith(".json")) {
|
|
6217
5955
|
parsed = JSON.parse(raw);
|
|
@@ -6272,7 +6010,7 @@ registerCheck(check19);
|
|
|
6272
6010
|
|
|
6273
6011
|
// src/checks/source/htmlhint.ts
|
|
6274
6012
|
import { existsSync as existsSync7 } from "node:fs";
|
|
6275
|
-
import { readFile as
|
|
6013
|
+
import { readFile as readFile10 } from "node:fs/promises";
|
|
6276
6014
|
import htmlhint from "htmlhint";
|
|
6277
6015
|
var { HTMLHint } = htmlhint;
|
|
6278
6016
|
var CONFIG_NAMES2 = [".htmlhintrc"];
|
|
@@ -6292,8 +6030,8 @@ var check20 = {
|
|
|
6292
6030
|
const resolvedConfig = findConfigFile(ctx.inputDir, CONFIG_NAMES2, configPath);
|
|
6293
6031
|
if (!resolvedConfig && !configPath)
|
|
6294
6032
|
return [];
|
|
6295
|
-
const ruleset = resolvedConfig ? JSON.parse(await
|
|
6296
|
-
const html = await
|
|
6033
|
+
const ruleset = resolvedConfig ? JSON.parse(await readFile10(resolvedConfig, "utf8")) : HTMLHint.defaultRuleset;
|
|
6034
|
+
const html = await readFile10(ctx.htmlPath, "utf8");
|
|
6297
6035
|
const messages = HTMLHint.verify(html, ruleset);
|
|
6298
6036
|
return messages.map((m) => ({
|
|
6299
6037
|
checkId: check20.id,
|
|
@@ -6308,7 +6046,7 @@ var check20 = {
|
|
|
6308
6046
|
registerCheck(check20);
|
|
6309
6047
|
|
|
6310
6048
|
// src/checks/source/stylelint.ts
|
|
6311
|
-
import { readFile as
|
|
6049
|
+
import { readFile as readFile11 } from "node:fs/promises";
|
|
6312
6050
|
|
|
6313
6051
|
// src/lib/printsafe.ts
|
|
6314
6052
|
import postcss from "postcss";
|
|
@@ -6650,7 +6388,7 @@ function checkCssRaw(css, from) {
|
|
|
6650
6388
|
warnings.push({
|
|
6651
6389
|
rule: ruleRiskyProps,
|
|
6652
6390
|
severity: "warning",
|
|
6653
|
-
message: `"${decl.prop}: ${decl.value}"
|
|
6391
|
+
message: `"${decl.prop}: ${decl.value}" is at risk in PDF/X exports (--format pdfx): Chromium emits repeating-*-gradient() and conic-gradient() in a form Ghostscript has been seen to paint as nothing or as irregular stripes, so it can print blank or distorted, unless the page also uses transparency and Ghostscript flattens the whole page to an image, which keeps the gradient but loses that page's live text. Plain PDF output is unaffected. Use linear-gradient() or radial-gradient() instead; for 0deg/90deg stripes write "linear-gradient(90deg, #b33 0 6px, #c8c5bf 6px 10px)" with "background-size: 10px 100%", and for anything else a small tiled image.`,
|
|
6654
6392
|
...nodeLoc(decl)
|
|
6655
6393
|
});
|
|
6656
6394
|
} else if (isUnpairedFitContentWidth(decl)) {
|
|
@@ -6715,7 +6453,7 @@ var check21 = {
|
|
|
6715
6453
|
for (const file of files) {
|
|
6716
6454
|
let css;
|
|
6717
6455
|
try {
|
|
6718
|
-
css = await
|
|
6456
|
+
css = await readFile11(file, "utf8");
|
|
6719
6457
|
} catch (err) {
|
|
6720
6458
|
results.push({
|
|
6721
6459
|
checkId: check21.id,
|
|
@@ -6742,7 +6480,7 @@ var check21 = {
|
|
|
6742
6480
|
registerCheck(check21);
|
|
6743
6481
|
|
|
6744
6482
|
// src/checks/source/css-ownership.ts
|
|
6745
|
-
import { readFile as
|
|
6483
|
+
import { readFile as readFile12 } from "node:fs/promises";
|
|
6746
6484
|
|
|
6747
6485
|
// src/lib/style-resolver.ts
|
|
6748
6486
|
import { existsSync as existsSync8 } from "node:fs";
|
|
@@ -6810,7 +6548,7 @@ import postcss2 from "postcss";
|
|
|
6810
6548
|
import { parse as parseYaml3 } from "yaml";
|
|
6811
6549
|
var CONFIG_NAMES3 = [".gutterpress/css-contract.yaml", ".gutterpress/css-contract.yml"];
|
|
6812
6550
|
async function loadContract(configPath) {
|
|
6813
|
-
const raw = await
|
|
6551
|
+
const raw = await readFile12(configPath, "utf8");
|
|
6814
6552
|
const parsed = parseYaml3(raw);
|
|
6815
6553
|
if (parsed && typeof parsed === "object")
|
|
6816
6554
|
return parsed;
|
|
@@ -6961,7 +6699,7 @@ var check22 = {
|
|
|
6961
6699
|
continue;
|
|
6962
6700
|
let css;
|
|
6963
6701
|
try {
|
|
6964
|
-
css = await
|
|
6702
|
+
css = await readFile12(absFile, "utf8");
|
|
6965
6703
|
} catch {
|
|
6966
6704
|
continue;
|
|
6967
6705
|
}
|
|
@@ -7008,7 +6746,7 @@ import { dirname as dirname3, resolve as resolve5 } from "node:path";
|
|
|
7008
6746
|
|
|
7009
6747
|
// src/lib/asset-inline.ts
|
|
7010
6748
|
import { createHash as createHash2 } from "node:crypto";
|
|
7011
|
-
import { readFile as
|
|
6749
|
+
import { readFile as readFile13 } from "node:fs/promises";
|
|
7012
6750
|
import path7 from "node:path";
|
|
7013
6751
|
import postcss3 from "postcss";
|
|
7014
6752
|
var FONT_EXTS = new Set([".woff2", ".woff", ".ttf", ".otf"]);
|
|
@@ -7073,7 +6811,7 @@ function mimeFor(ext) {
|
|
|
7073
6811
|
}
|
|
7074
6812
|
async function readOrThrow(absPath, kind, referencedFrom) {
|
|
7075
6813
|
try {
|
|
7076
|
-
return await
|
|
6814
|
+
return await readFile13(absPath);
|
|
7077
6815
|
} catch {
|
|
7078
6816
|
throw new BuildError(`Missing ${kind}: ${absPath}
|
|
7079
6817
|
referenced from ${referencedFrom}
|
|
@@ -7216,7 +6954,7 @@ async function collectStyleDependencies(projectDir, stylePaths) {
|
|
|
7216
6954
|
found.add(abs);
|
|
7217
6955
|
let source;
|
|
7218
6956
|
try {
|
|
7219
|
-
source = await
|
|
6957
|
+
source = await readFile13(abs, "utf-8");
|
|
7220
6958
|
} catch {
|
|
7221
6959
|
return;
|
|
7222
6960
|
}
|
|
@@ -7293,7 +7031,7 @@ async function inlineShapeUrls(html, baseDir) {
|
|
|
7293
7031
|
continue;
|
|
7294
7032
|
let bytes;
|
|
7295
7033
|
try {
|
|
7296
|
-
bytes = await
|
|
7034
|
+
bytes = await readFile13(abs);
|
|
7297
7035
|
} catch {
|
|
7298
7036
|
continue;
|
|
7299
7037
|
}
|
|
@@ -7311,7 +7049,7 @@ async function inlineShapeUrls(html, baseDir) {
|
|
|
7311
7049
|
}
|
|
7312
7050
|
|
|
7313
7051
|
// src/checks/source/local-ref-parser.ts
|
|
7314
|
-
import { readFile as
|
|
7052
|
+
import { readFile as readFile14 } from "node:fs/promises";
|
|
7315
7053
|
function newlineOffsets(content) {
|
|
7316
7054
|
const offsets = [];
|
|
7317
7055
|
for (let i = 0;i < content.length; i++)
|
|
@@ -7380,7 +7118,7 @@ async function* renderedLocalRefs(ctx, checkId, results) {
|
|
|
7380
7118
|
for (const file of files) {
|
|
7381
7119
|
let refs;
|
|
7382
7120
|
try {
|
|
7383
|
-
refs = collectRenderedLocalRefs(await
|
|
7121
|
+
refs = collectRenderedLocalRefs(await readFile14(file, "utf8"));
|
|
7384
7122
|
} catch {
|
|
7385
7123
|
results.push(inspectionFailed(checkId, `Could not read source file: ${file}`, { file }));
|
|
7386
7124
|
continue;
|
|
@@ -7731,7 +7469,7 @@ var check24 = {
|
|
|
7731
7469
|
registerCheck(check24);
|
|
7732
7470
|
|
|
7733
7471
|
// src/checks/source/accessibility-alt-text.ts
|
|
7734
|
-
import { readFile as
|
|
7472
|
+
import { readFile as readFile15 } from "node:fs/promises";
|
|
7735
7473
|
var check25 = {
|
|
7736
7474
|
id: "source.accessibility.alt-text",
|
|
7737
7475
|
name: "Image Alt Text",
|
|
@@ -7745,7 +7483,7 @@ var check25 = {
|
|
|
7745
7483
|
const results = [];
|
|
7746
7484
|
for (const file of files) {
|
|
7747
7485
|
try {
|
|
7748
|
-
const content = await
|
|
7486
|
+
const content = await readFile15(file, "utf8");
|
|
7749
7487
|
const lines = content.split(`
|
|
7750
7488
|
`);
|
|
7751
7489
|
let inFence = false;
|
|
@@ -7789,7 +7527,7 @@ function extractImageAlts(line) {
|
|
|
7789
7527
|
registerCheck(check25);
|
|
7790
7528
|
|
|
7791
7529
|
// src/checks/source/accessibility-heading-order.ts
|
|
7792
|
-
import { readFile as
|
|
7530
|
+
import { readFile as readFile16 } from "node:fs/promises";
|
|
7793
7531
|
var check26 = {
|
|
7794
7532
|
id: "source.accessibility.heading-order",
|
|
7795
7533
|
name: "Heading Order",
|
|
@@ -7803,7 +7541,7 @@ var check26 = {
|
|
|
7803
7541
|
const results = [];
|
|
7804
7542
|
for (const file of files) {
|
|
7805
7543
|
try {
|
|
7806
|
-
const content = await
|
|
7544
|
+
const content = await readFile16(file, "utf8");
|
|
7807
7545
|
const lines = content.split(`
|
|
7808
7546
|
`);
|
|
7809
7547
|
let inFence = false;
|
|
@@ -7845,7 +7583,7 @@ var check26 = {
|
|
|
7845
7583
|
registerCheck(check26);
|
|
7846
7584
|
|
|
7847
7585
|
// src/checks/source/layout-markers.ts
|
|
7848
|
-
import { readFile as
|
|
7586
|
+
import { readFile as readFile17 } from "node:fs/promises";
|
|
7849
7587
|
|
|
7850
7588
|
// src/lib/unknown-classes.ts
|
|
7851
7589
|
import postcss4 from "postcss";
|
|
@@ -7948,7 +7686,7 @@ async function collectKnownClasses(ctx, plugins) {
|
|
|
7948
7686
|
const sheets = (await collectStyleDependencies(ctx.inputDir, roots)).filter((f) => /\.css$/i.test(f));
|
|
7949
7687
|
for (const sheet of sheets) {
|
|
7950
7688
|
try {
|
|
7951
|
-
addCssClasses(await
|
|
7689
|
+
addCssClasses(await readFile17(sheet, "utf8"), names);
|
|
7952
7690
|
} catch {}
|
|
7953
7691
|
}
|
|
7954
7692
|
return names;
|
|
@@ -7972,7 +7710,7 @@ var check27 = {
|
|
|
7972
7710
|
const knownClasses = () => known ??= collectKnownClasses(ctx, plugins);
|
|
7973
7711
|
for (const file of files) {
|
|
7974
7712
|
try {
|
|
7975
|
-
const content = await
|
|
7713
|
+
const content = await readFile17(file, "utf8");
|
|
7976
7714
|
const env = {};
|
|
7977
7715
|
const tokens = md.parse(content, env);
|
|
7978
7716
|
md.renderer.render(tokens, md.options, env);
|
|
@@ -8012,7 +7750,7 @@ var check27 = {
|
|
|
8012
7750
|
registerCheck(check27);
|
|
8013
7751
|
|
|
8014
7752
|
// src/checks/source/merge-markers.ts
|
|
8015
|
-
import { readFile as
|
|
7753
|
+
import { readFile as readFile18 } from "node:fs/promises";
|
|
8016
7754
|
import path9 from "node:path";
|
|
8017
7755
|
|
|
8018
7756
|
// src/checks/asset/extensions.ts
|
|
@@ -8054,7 +7792,7 @@ var check28 = {
|
|
|
8054
7792
|
for (const file of textFiles) {
|
|
8055
7793
|
let content;
|
|
8056
7794
|
try {
|
|
8057
|
-
content = await
|
|
7795
|
+
content = await readFile18(file, "utf8");
|
|
8058
7796
|
} catch {
|
|
8059
7797
|
results.push(inspectionFailed(check28.id, `Could not read source file: ${file}`, { file }));
|
|
8060
7798
|
continue;
|
|
@@ -8114,7 +7852,7 @@ var check28 = {
|
|
|
8114
7852
|
registerCheck(check28);
|
|
8115
7853
|
|
|
8116
7854
|
// src/checks/source/characters.ts
|
|
8117
|
-
import { readFile as
|
|
7855
|
+
import { readFile as readFile19 } from "node:fs/promises";
|
|
8118
7856
|
|
|
8119
7857
|
// src/checks/source/character-table.ts
|
|
8120
7858
|
var CHARACTER_PATTERN = new RegExp("[\\u0000-\\u0008\\u000B\\u000C\\u000E-\\u001F\\u007F-\\u00A0\\u00AD\\u00B4\\u02BC" + "\\u061C\\u2000-\\u2015\\u2018\\u2019\\u201B-\\u201D\\u201F\\u2022\\u2026" + "\\u2028-\\u202F\\u2032\\u2033\\u205F\\u2060\\u2066-\\u2069\\u2190\\u2192" + "\\u2194\\u21D2\\u2212\\u25AA\\u25E6\\u2605\\u2713\\u2714\\u2717\\u3000" + "\\uE000-\\uF8FF\\uFEFF\\uFF02\\uFF07\\uFFFD]" + "|\\p{Emoji_Presentation}|\\p{Extended_Pictographic}(?=\\uFE0F)", "gu");
|
|
@@ -8237,7 +7975,7 @@ var check29 = {
|
|
|
8237
7975
|
for (const file of (ctx.markdownFiles ?? []).slice().sort()) {
|
|
8238
7976
|
let content;
|
|
8239
7977
|
try {
|
|
8240
|
-
content = await
|
|
7978
|
+
content = await readFile19(file, "utf8");
|
|
8241
7979
|
} catch {
|
|
8242
7980
|
results.push(inspectionFailed(check29.id, `Could not read source file: ${file}`, { file }));
|
|
8243
7981
|
continue;
|
|
@@ -8277,16 +8015,16 @@ var check29 = {
|
|
|
8277
8015
|
registerCheck(check29);
|
|
8278
8016
|
|
|
8279
8017
|
// src/checks/asset/image-file-size.ts
|
|
8280
|
-
import { stat as
|
|
8018
|
+
import { stat as stat3 } from "node:fs/promises";
|
|
8281
8019
|
|
|
8282
8020
|
// src/lib/image-inspect.ts
|
|
8283
|
-
import { stat as
|
|
8021
|
+
import { stat as stat2, readFile as readFile20 } from "node:fs/promises";
|
|
8284
8022
|
var DEFAULT_DPI = 72;
|
|
8285
8023
|
var cache = new Map;
|
|
8286
8024
|
async function inspectImage(path10) {
|
|
8287
8025
|
let st;
|
|
8288
8026
|
try {
|
|
8289
|
-
st = await
|
|
8027
|
+
st = await stat2(path10);
|
|
8290
8028
|
} catch {
|
|
8291
8029
|
return null;
|
|
8292
8030
|
}
|
|
@@ -8295,7 +8033,7 @@ async function inspectImage(path10) {
|
|
|
8295
8033
|
return hit.info;
|
|
8296
8034
|
let info3 = null;
|
|
8297
8035
|
try {
|
|
8298
|
-
const buf = await
|
|
8036
|
+
const buf = await readFile20(path10);
|
|
8299
8037
|
info3 = parseImage(buf);
|
|
8300
8038
|
} catch {
|
|
8301
8039
|
info3 = null;
|
|
@@ -8517,7 +8255,7 @@ var check30 = {
|
|
|
8517
8255
|
const results = [];
|
|
8518
8256
|
for (const file of files) {
|
|
8519
8257
|
try {
|
|
8520
|
-
const info3 = await
|
|
8258
|
+
const info3 = await stat3(file);
|
|
8521
8259
|
if (info3.size > maxSize) {
|
|
8522
8260
|
const sizeMb = (info3.size / 1e6).toFixed(1);
|
|
8523
8261
|
const maxMb = (maxSize / 1e6).toFixed(1);
|
|
@@ -8855,7 +8593,7 @@ var check37 = {
|
|
|
8855
8593
|
registerCheck(check37);
|
|
8856
8594
|
|
|
8857
8595
|
// src/checks/heuristic/section-density.ts
|
|
8858
|
-
import { readFile as
|
|
8596
|
+
import { readFile as readFile21 } from "node:fs/promises";
|
|
8859
8597
|
var check38 = {
|
|
8860
8598
|
id: "heuristic.chunking.section-density",
|
|
8861
8599
|
name: "Section Density",
|
|
@@ -8872,7 +8610,7 @@ var check38 = {
|
|
|
8872
8610
|
const results = [];
|
|
8873
8611
|
for (const file of files) {
|
|
8874
8612
|
try {
|
|
8875
|
-
const content = await
|
|
8613
|
+
const content = await readFile21(file, "utf8");
|
|
8876
8614
|
const lines = content.split(`
|
|
8877
8615
|
`);
|
|
8878
8616
|
let currentSectionStart = 0;
|
|
@@ -9176,7 +8914,7 @@ async function restoreForCommand(dir, options) {
|
|
|
9176
8914
|
}
|
|
9177
8915
|
|
|
9178
8916
|
// src/lib/markdown/index.ts
|
|
9179
|
-
import { readdir as readdir3, readFile as
|
|
8917
|
+
import { readdir as readdir3, readFile as readFile22, writeFile as writeFile2, mkdir as mkdir4 } from "node:fs/promises";
|
|
9180
8918
|
|
|
9181
8919
|
// src/lib/remote-auth/sync-messages.ts
|
|
9182
8920
|
function isOnlineSibling(filepath) {
|
|
@@ -9198,6 +8936,20 @@ function canonicalChapterId(p) {
|
|
|
9198
8936
|
return s;
|
|
9199
8937
|
}
|
|
9200
8938
|
|
|
8939
|
+
// src/engine/shared/print-area.ts
|
|
8940
|
+
function printAreaMeta(page) {
|
|
8941
|
+
const area = JSON.stringify({
|
|
8942
|
+
width: page.width,
|
|
8943
|
+
height: page.height,
|
|
8944
|
+
bleed: page.bleed ?? 0,
|
|
8945
|
+
safe: page.safe ?? 0,
|
|
8946
|
+
artSafe: page.artSafe,
|
|
8947
|
+
preset: page.preset,
|
|
8948
|
+
spec: page.spec
|
|
8949
|
+
});
|
|
8950
|
+
return `<meta name="gp-print-area" content='${area.replace(/&/g, "&").replace(/'/g, "'")}'>`;
|
|
8951
|
+
}
|
|
8952
|
+
|
|
9201
8953
|
// src/lib/markdown/assemble.ts
|
|
9202
8954
|
async function assembleBookHtml(opts) {
|
|
9203
8955
|
const title = opts.title ?? "Document";
|
|
@@ -9263,7 +9015,8 @@ ${projectCss.trim()}` : null
|
|
|
9263
9015
|
<html lang="en"${printAttrs}>
|
|
9264
9016
|
<head>
|
|
9265
9017
|
<meta charset="UTF-8">
|
|
9266
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0"
|
|
9018
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">${opts.printArea ? `
|
|
9019
|
+
${printAreaMeta(opts.printArea)}` : ""}
|
|
9267
9020
|
<title>${title}</title>${preloadTags}
|
|
9268
9021
|
<style data-project-css>
|
|
9269
9022
|
${inlineCss}
|
|
@@ -9318,11 +9071,12 @@ ${css.trim()}
|
|
|
9318
9071
|
}
|
|
9319
9072
|
return assembleBookHtml({
|
|
9320
9073
|
files,
|
|
9321
|
-
readText: (relPath) =>
|
|
9074
|
+
readText: (relPath) => readFile22(join2(inputDir, canonicalChapterId(relPath)), "utf-8"),
|
|
9322
9075
|
projectCss: inlined.css,
|
|
9323
9076
|
preloadImages: cssAssetCopies.map((c) => c.to),
|
|
9324
9077
|
title: opts.title,
|
|
9325
9078
|
print: opts.print,
|
|
9079
|
+
printArea: opts.printArea,
|
|
9326
9080
|
plugins: opts.plugins,
|
|
9327
9081
|
pluginCss,
|
|
9328
9082
|
annotateSourceChapters: opts.annotateSourceChapters,
|
|
@@ -9335,6 +9089,7 @@ async function renderChaptersToFile(inputDir, outDir, opts = {}) {
|
|
|
9335
9089
|
const html = await renderChapters(inputDir, {
|
|
9336
9090
|
title: opts.title,
|
|
9337
9091
|
print: opts.print,
|
|
9092
|
+
printArea: opts.printArea,
|
|
9338
9093
|
styles: opts.styles,
|
|
9339
9094
|
files: opts.files,
|
|
9340
9095
|
plugins: opts.plugins,
|
|
@@ -9350,7 +9105,7 @@ async function renderChaptersToFile(inputDir, outDir, opts = {}) {
|
|
|
9350
9105
|
}
|
|
9351
9106
|
|
|
9352
9107
|
// src/lib/markdownlint-fix.ts
|
|
9353
|
-
import { readFile as
|
|
9108
|
+
import { readFile as readFile23, writeFile as writeFile3 } from "node:fs/promises";
|
|
9354
9109
|
import { applyFixes } from "markdownlint";
|
|
9355
9110
|
import { lint as lint2 } from "markdownlint/sync";
|
|
9356
9111
|
async function uncommittedAmong(inputDir, files) {
|
|
@@ -9390,7 +9145,7 @@ async function applyMarkdownlintFixes(ctx) {
|
|
|
9390
9145
|
for (const [file, violations] of Object.entries(results)) {
|
|
9391
9146
|
if (!Array.isArray(violations) || violations.length === 0)
|
|
9392
9147
|
continue;
|
|
9393
|
-
const before = await
|
|
9148
|
+
const before = await readFile23(file, "utf8");
|
|
9394
9149
|
const after = applyFixes(before, violations);
|
|
9395
9150
|
if (after !== before)
|
|
9396
9151
|
pending.push({ file, content: after });
|
|
@@ -9903,7 +9658,7 @@ import { randomBytes } from "node:crypto";
|
|
|
9903
9658
|
|
|
9904
9659
|
// src/lib/build-fingerprint.ts
|
|
9905
9660
|
import * as fs from "node:fs";
|
|
9906
|
-
import { mkdir as mkdir5, readFile as
|
|
9661
|
+
import { mkdir as mkdir5, readFile as readFile24, writeFile as writeFile4 } from "node:fs/promises";
|
|
9907
9662
|
import { createHash as createHash4 } from "node:crypto";
|
|
9908
9663
|
import path12 from "node:path";
|
|
9909
9664
|
import git from "isomorphic-git";
|
|
@@ -9990,8 +9745,8 @@ async function getEngineBundleHash() {
|
|
|
9990
9745
|
getAssetPath("engine/gutterpress-agent.js")
|
|
9991
9746
|
]);
|
|
9992
9747
|
const [viewerBytes, agentBytes] = await Promise.all([
|
|
9993
|
-
|
|
9994
|
-
|
|
9748
|
+
readFile24(viewerPath),
|
|
9749
|
+
readFile24(agentPath)
|
|
9995
9750
|
]);
|
|
9996
9751
|
const hash = createHash4("sha256");
|
|
9997
9752
|
hash.update(viewerBytes);
|
|
@@ -10054,7 +9809,10 @@ async function writeBuildFingerprint(input) {
|
|
|
10054
9809
|
resolvedFlavor: input.pdfx.resolvedFlavor,
|
|
10055
9810
|
iccPath: input.pdfx.iccPath,
|
|
10056
9811
|
stripAnnotations: input.pdfx.stripAnnotations,
|
|
10057
|
-
blackText: input.pdfx.blackText ?? null
|
|
9812
|
+
blackText: input.pdfx.blackText ?? null,
|
|
9813
|
+
transparency: input.pdfx.transparency ?? null,
|
|
9814
|
+
flattenPages: input.pdfx.flattenPages ?? null,
|
|
9815
|
+
rasterDpi: input.pdfx.rasterDpi ?? null
|
|
10058
9816
|
},
|
|
10059
9817
|
outputDir: input.recordedOutputDir ? path12.resolve(input.recordedOutputDir) : outputDir
|
|
10060
9818
|
},
|
|
@@ -10209,6 +9967,7 @@ async function renderBook(ctx) {
|
|
|
10209
9967
|
const htmlFile = await renderChaptersToFile(renderDir, workDir, {
|
|
10210
9968
|
title: config.title,
|
|
10211
9969
|
print: config.print,
|
|
9970
|
+
printArea: { ...config.page, preset: config.preset, spec: config.spec },
|
|
10212
9971
|
styles: config.styles,
|
|
10213
9972
|
files: config.source.files,
|
|
10214
9973
|
plugins,
|
|
@@ -10361,7 +10120,7 @@ class PdfOutput {
|
|
|
10361
10120
|
const rawPdf = pdfxMode ? path13.join(stage, "raw.pdf") : path13.resolve(pdfFile);
|
|
10362
10121
|
await fsp2.mkdir(path13.dirname(path13.resolve(pdfFile)), { recursive: true });
|
|
10363
10122
|
log.info("Rendering HTML to PDF via the Gutterpress engine (native Chromium pagination)");
|
|
10364
|
-
const { buildNativePdf } = await import("./engine-
|
|
10123
|
+
const { buildNativePdf } = await import("./engine-67f68bxs.js");
|
|
10365
10124
|
const engineDiagnostics = await buildNativePdf(htmlFile, rawPdf, {
|
|
10366
10125
|
title: config.title,
|
|
10367
10126
|
author: config.authors.length > 0 ? config.authors.join(", ") : undefined,
|
|
@@ -10383,12 +10142,40 @@ class PdfOutput {
|
|
|
10383
10142
|
if (pdfxMode) {
|
|
10384
10143
|
const icc = opts.iccPath ?? config.pdfx.icc;
|
|
10385
10144
|
effectiveIccPath = await resolveIccProfile(icc, manifestDir, opts.iccPath);
|
|
10386
|
-
|
|
10387
|
-
|
|
10145
|
+
const rawBytes = await fsp2.readFile(rawPdf);
|
|
10146
|
+
const transparent = await transparentPages(rawBytes);
|
|
10147
|
+
const blankGradientPages = await findPostScriptShadingPages(rawBytes);
|
|
10148
|
+
const flattenedGradientPages = blankGradientPages.filter((n) => transparent.includes(n));
|
|
10149
|
+
const vectorGradientPages = blankGradientPages.filter((n) => !transparent.includes(n));
|
|
10150
|
+
const GRADIENT_FIX = "Replace it with a plain linear-gradient() or radial-gradient(), or a small tiled image. For 0deg/90deg stripes, `linear-gradient(90deg, #b33 0 6px, #c8c5bf 6px 10px)` with `background-size: 10px 100%` converts correctly.";
|
|
10151
|
+
const pageList = (pages) => `Page${pages.length === 1 ? "" : "s"} ${pages.join(", ")}`;
|
|
10152
|
+
if (vectorGradientPages.length > 0) {
|
|
10153
|
+
log.warn(`${pageList(vectorGradientPages)}: a repeating-*-gradient() or conic-gradient() ` + "can print blank or distorted — " + `Ghostscript has been seen to paint nothing, or irregular stripes, for it when converting to PDF/X; check the page visually. ${GRADIENT_FIX}`);
|
|
10154
|
+
}
|
|
10155
|
+
if (flattenedGradientPages.length > 0 && config.pdfx.transparency !== "preserve-text") {
|
|
10156
|
+
log.warn(`${pageList(flattenedGradientPages)}: a repeating-*-gradient() or conic-gradient() is painted only as part of the one raster image Ghostscript makes of the whole page, so the page loses its embedded fonts and searchable text. Check the page visually. ${GRADIENT_FIX}`);
|
|
10157
|
+
}
|
|
10158
|
+
const flattenPages = config.pdfx.flattenPages;
|
|
10159
|
+
if (transparent.length > 0 && config.pdfx.transparency === "preserve-text") {
|
|
10160
|
+
const { unsplittableTextReasons } = await import("./pdf-inspect-zdmy7qca.js");
|
|
10161
|
+
const reasons = await unsplittableTextReasons(rawBytes, transparent).catch((err) => {
|
|
10162
|
+
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.`);
|
|
10163
|
+
return null;
|
|
10164
|
+
});
|
|
10165
|
+
if (reasons) {
|
|
10166
|
+
const plan = planTransparentPages(transparent, reasons, flattenPages, blankGradientPages);
|
|
10167
|
+
await flattenTransparentPages(rawPdf, plan.split, stage, config.pdfx.rasterDpi);
|
|
10168
|
+
reportTransparentPlan(plan, pdfxMode, config.pdfx.rasterDpi ?? 300, pageList);
|
|
10169
|
+
}
|
|
10388
10170
|
}
|
|
10389
|
-
const
|
|
10390
|
-
if (
|
|
10391
|
-
log.warn(
|
|
10171
|
+
const unused = flattenPages.filter((n) => !transparent.includes(n));
|
|
10172
|
+
if (flattenPages.length > 0 && config.pdfx.transparency !== "preserve-text") {
|
|
10173
|
+
log.warn("pdfx.flattenPages has no effect without pdfx.transparency: preserve-text.");
|
|
10174
|
+
} else if (unused.length > 0) {
|
|
10175
|
+
log.warn(`pdfx.flattenPages lists ${pageList(unused).toLowerCase()}, which ${unused.length === 1 ? "has" : "have"} no transparency (or do not exist): nothing to flatten there.`);
|
|
10176
|
+
}
|
|
10177
|
+
if (transparent.length > 0 && config.pdfx.transparency !== "preserve-text") {
|
|
10178
|
+
log.warn("This book uses transparency — an image with an alpha channel, or a CSS " + `rule like \`opacity\` or \`mix-blend-mode\`. PDF/${pdfxMode === "x1a" ? "X-1a" : "X-3"} has no way to represent that (both are based on PDF 1.3, which predates PDF transparency), so Ghostscript will flatten every page that uses it into a single raster ` + "image — that page loses its embedded fonts and searchable text in the " + "PDF/X output. To keep vector text, remove the `opacity`/blend rule and flatten any alpha-channel image against its intended background before including it (export it with no alpha channel), or build --format pdf instead of pdfx if this book doesn't need print-ready CMYK. Or set `pdfx.transparency: preserve-text` to keep the text live on the pages where that is possible. `pdfx.rasterDpi` sets the resolution of those page images (default 720).");
|
|
10392
10179
|
}
|
|
10393
10180
|
const shouldStrip = opts.stripAnnotations ?? config.pdfx.stripAnnotations;
|
|
10394
10181
|
shouldStripAnnotations = shouldStrip;
|
|
@@ -10431,7 +10218,10 @@ class PdfOutput {
|
|
|
10431
10218
|
resolvedFlavor: config.pdfx.flavor,
|
|
10432
10219
|
iccPath: effectiveIccPath,
|
|
10433
10220
|
stripAnnotations: shouldStripAnnotations,
|
|
10434
|
-
blackText: pdfxMode ? config.pdfx.blackText : null
|
|
10221
|
+
blackText: pdfxMode ? config.pdfx.blackText : null,
|
|
10222
|
+
transparency: pdfxMode ? config.pdfx.transparency : null,
|
|
10223
|
+
flattenPages: pdfxMode ? config.pdfx.flattenPages : null,
|
|
10224
|
+
rasterDpi: pdfxMode ? config.pdfx.rasterDpi ?? null : null
|
|
10435
10225
|
}
|
|
10436
10226
|
}, `Wrote: ${reportedPdf}`, { htmlPath: htmlFile, pdfPath: reportedPdf }, pdfName, engineDiagnostics);
|
|
10437
10227
|
} finally {
|
|
@@ -10468,6 +10258,35 @@ async function runBuild(opts) {
|
|
|
10468
10258
|
await fsp2.rm(ctx.workDir, { recursive: true, force: true });
|
|
10469
10259
|
}
|
|
10470
10260
|
}
|
|
10261
|
+
var FALLBACK_CAUSE = {
|
|
10262
|
+
listed: "listed in pdfx.flattenPages",
|
|
10263
|
+
"text-transparency": "text drawn with transparency or blending (opacity, mix-blend-mode, a soft mask, a translucent text-shadow); keep that text opaque",
|
|
10264
|
+
"type3-font": "text in a Type 3 font: for a synthetic bold (a weight the font has no face for), use a face with that weight or set the font's own weight; for -webkit-text-stroke, remove the stroke or accept this fallback",
|
|
10265
|
+
"text-pattern-or-clip": 'text filled with a pattern or used as a clip (SVG fill="url(#…)", gradient text, background-clip: text)',
|
|
10266
|
+
gradient: "a repeating or conic gradient; use a linear or radial gradient, or a small tiled image"
|
|
10267
|
+
};
|
|
10268
|
+
function reportTransparentPlan({ split, artOnly, kept }, pdfxMode, dpi, pageList) {
|
|
10269
|
+
const one = (pages, singular, plural) => pages.length === 1 ? singular : plural;
|
|
10270
|
+
if (split.length > 0) {
|
|
10271
|
+
log.warn(`${pageList(split)} ${one(split, "uses", "use")} transparency, which PDF/${pdfxMode === "x1a" ? "X-1a" : "X-3"} (PDF 1.3) cannot represent. Each was flattened to a ${dpi} DPI picture with its text kept live on top (pdfx.transparency: preserve-text), so fonts and searchable text survive. On those pages, rules, backgrounds and shapes are raster, and text always sits above the artwork: text another element covers shows through. List a page in pdfx.flattenPages to flatten it whole instead.`);
|
|
10272
|
+
}
|
|
10273
|
+
if (artOnly.length > 0) {
|
|
10274
|
+
log.info(`${pageList(artOnly)} ${one(artOnly, "uses", "use")} transparency but ${one(artOnly, "shows", "show")} no text, so there is no text to keep: Ghostscript flattens ${one(artOnly, "it", "each")} whole (resolution: pdfx.rasterDpi).`);
|
|
10275
|
+
}
|
|
10276
|
+
if (kept.size > 0) {
|
|
10277
|
+
const pages = [...kept.keys()];
|
|
10278
|
+
const byCause = new Map;
|
|
10279
|
+
for (const [n, cause] of kept)
|
|
10280
|
+
byCause.set(cause, [...byCause.get(cause) ?? [], n]);
|
|
10281
|
+
const lines = [...byCause].map(([cause, ns]) => ` - ${one(ns, "page", "pages")} ${ns.join(", ")}: ${FALLBACK_CAUSE[cause]}`);
|
|
10282
|
+
log.warn(`${pageList(pages)} could not keep ${one(pages, "its", "their")} text live; Ghostscript will flatten ${one(pages, "that page", "each of those pages")} into one raster image, losing its embedded fonts and searchable text. Each page lists the first cause found; fixing it can reveal another:
|
|
10283
|
+
` + lines.join(`
|
|
10284
|
+
`));
|
|
10285
|
+
}
|
|
10286
|
+
if (split.length === 0 && [...kept.values()].some((cause) => cause !== "listed")) {
|
|
10287
|
+
log.warn("pdfx.transparency: preserve-text kept no page's text live in this book: every page with transparency and text falls back (see above).");
|
|
10288
|
+
}
|
|
10289
|
+
}
|
|
10471
10290
|
|
|
10472
10291
|
// src/lib/open-path.ts
|
|
10473
10292
|
import { spawn } from "node:child_process";
|
|
@@ -10501,7 +10320,7 @@ function openPath(filePath) {
|
|
|
10501
10320
|
import path16 from "path";
|
|
10502
10321
|
import { tmpdir } from "os";
|
|
10503
10322
|
import { randomBytes as randomBytes2 } from "crypto";
|
|
10504
|
-
import { readdir as readdir4, readFile as
|
|
10323
|
+
import { readdir as readdir4, readFile as readFile25, writeFile as writeFile5 } from "node:fs/promises";
|
|
10505
10324
|
|
|
10506
10325
|
// src/utils/file-utils.ts
|
|
10507
10326
|
import { promises as fs3 } from "fs";
|
|
@@ -10604,6 +10423,7 @@ async function renderPreviewBook(inputPath, config, opts) {
|
|
|
10604
10423
|
return renderChapters(inputPath, {
|
|
10605
10424
|
title: config.title ?? "Document",
|
|
10606
10425
|
print: config.print,
|
|
10426
|
+
printArea: config.printArea,
|
|
10607
10427
|
styles: config.styles,
|
|
10608
10428
|
files: opts.files,
|
|
10609
10429
|
plugins,
|
|
@@ -10618,19 +10438,8 @@ async function renderPreviewBook(inputPath, config, opts) {
|
|
|
10618
10438
|
}
|
|
10619
10439
|
});
|
|
10620
10440
|
}
|
|
10621
|
-
function injectPreviewScripts(html
|
|
10622
|
-
const
|
|
10623
|
-
width: page.width,
|
|
10624
|
-
height: page.height,
|
|
10625
|
-
bleed: page.bleed ?? 0,
|
|
10626
|
-
safe: page.safe ?? 0,
|
|
10627
|
-
artSafe: page.artSafe,
|
|
10628
|
-
preset: page.preset,
|
|
10629
|
-
spec: page.spec
|
|
10630
|
-
}) : "";
|
|
10631
|
-
const meta = area ? ` <meta name="gp-print-area" content='${area.replace(/&/g, "&").replace(/'/g, "'")}'>
|
|
10632
|
-
` : "";
|
|
10633
|
-
const scripts = meta + ` <script src="/engine/gutterpress-viewer.js"></script>
|
|
10441
|
+
function injectPreviewScripts(html) {
|
|
10442
|
+
const scripts = ` <script src="/engine/gutterpress-viewer.js"></script>
|
|
10634
10443
|
` + `<script src="/preview/scripts/preview-interface.js"></script>
|
|
10635
10444
|
` + `<script src="/preview/scripts/preview-bridge.js"></script>
|
|
10636
10445
|
`;
|
|
@@ -10645,7 +10454,10 @@ async function generateAndWriteHtml(inputPath, tempDir, config, cssAssets, image
|
|
|
10645
10454
|
}
|
|
10646
10455
|
const nextAssets = new Map;
|
|
10647
10456
|
const nextImageRefs = new Set;
|
|
10648
|
-
const html = await renderPreviewBook(inputPath,
|
|
10457
|
+
const html = await renderPreviewBook(inputPath, {
|
|
10458
|
+
...config,
|
|
10459
|
+
printArea: config.page && { ...config.page, preset: config.preset, spec: config.spec }
|
|
10460
|
+
}, {
|
|
10649
10461
|
files: config.source?.files ?? null,
|
|
10650
10462
|
onCssAssets: (copies) => {
|
|
10651
10463
|
for (const copy of copies)
|
|
@@ -10664,7 +10476,7 @@ async function generateAndWriteHtml(inputPath, tempDir, config, cssAssets, image
|
|
|
10664
10476
|
for (const ref of nextImageRefs)
|
|
10665
10477
|
imageRefs.add(ref);
|
|
10666
10478
|
}
|
|
10667
|
-
await fsp3.writeFile(path15.join(tempDir, BOOK_HTML_FILENAME), injectPreviewScripts(html
|
|
10479
|
+
await fsp3.writeFile(path15.join(tempDir, BOOK_HTML_FILENAME), injectPreviewScripts(html), "utf-8");
|
|
10668
10480
|
}
|
|
10669
10481
|
function isDotPathUnderRoot(candidatePath, root) {
|
|
10670
10482
|
const normalizedRoot = root.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
@@ -11062,7 +10874,7 @@ async function cleanupOrphanTempDirs() {
|
|
|
11062
10874
|
const dir = path16.join(TEMP_DIR_BASE, entry);
|
|
11063
10875
|
const pidFile = path16.join(dir, PID_FILE_NAME);
|
|
11064
10876
|
try {
|
|
11065
|
-
const raw = await
|
|
10877
|
+
const raw = await readFile25(pidFile, "utf8");
|
|
11066
10878
|
const pid = parseInt(raw.trim(), 10);
|
|
11067
10879
|
if (!isProcessAlive(pid)) {
|
|
11068
10880
|
debug(`Removing orphan temp dir ${dir} (pid ${pid} not alive)`);
|
|
@@ -11169,7 +10981,7 @@ function createServerState(inputPath, tempDir, config, options) {
|
|
|
11169
10981
|
import http from "node:http";
|
|
11170
10982
|
import net from "node:net";
|
|
11171
10983
|
import { createHash as createHash5, randomUUID as randomUUID3 } from "node:crypto";
|
|
11172
|
-
import { readFile as
|
|
10984
|
+
import { readFile as readFile26, stat as stat4 } from "node:fs/promises";
|
|
11173
10985
|
import path17 from "path";
|
|
11174
10986
|
import { WebSocket, WebSocketServer } from "ws";
|
|
11175
10987
|
var HMR_PATH = "/__gutterpress-hmr";
|
|
@@ -11228,7 +11040,7 @@ async function findAvailablePort(startPort, host = "127.0.0.1") {
|
|
|
11228
11040
|
async function serveStatic(absPath, res, cacheControl = "no-store", extraHeaders = {}) {
|
|
11229
11041
|
let filePath = absPath;
|
|
11230
11042
|
try {
|
|
11231
|
-
const s = await
|
|
11043
|
+
const s = await stat4(filePath);
|
|
11232
11044
|
if (s.isDirectory())
|
|
11233
11045
|
filePath = path17.join(filePath, "index.html");
|
|
11234
11046
|
} catch {
|
|
@@ -11238,7 +11050,7 @@ async function serveStatic(absPath, res, cacheControl = "no-store", extraHeaders
|
|
|
11238
11050
|
}
|
|
11239
11051
|
let data;
|
|
11240
11052
|
try {
|
|
11241
|
-
data = await
|
|
11053
|
+
data = await readFile26(filePath);
|
|
11242
11054
|
} catch {
|
|
11243
11055
|
res.writeHead(404);
|
|
11244
11056
|
res.end("Not Found");
|
|
@@ -11267,7 +11079,7 @@ async function serveRevalidatedStatic(req, absPath, res, validators) {
|
|
|
11267
11079
|
}
|
|
11268
11080
|
let fileStat;
|
|
11269
11081
|
try {
|
|
11270
|
-
fileStat = await
|
|
11082
|
+
fileStat = await stat4(absPath, { bigint: true });
|
|
11271
11083
|
} catch {
|
|
11272
11084
|
await serveStatic(absPath, res);
|
|
11273
11085
|
return;
|
|
@@ -11287,7 +11099,7 @@ async function serveRevalidatedStatic(req, absPath, res, validators) {
|
|
|
11287
11099
|
let data;
|
|
11288
11100
|
if (!validator || validator.stamp !== stamp) {
|
|
11289
11101
|
try {
|
|
11290
|
-
data = await
|
|
11102
|
+
data = await readFile26(absPath);
|
|
11291
11103
|
} catch {
|
|
11292
11104
|
await serveStatic(absPath, res);
|
|
11293
11105
|
return;
|
|
@@ -11315,7 +11127,7 @@ async function isMissingReferencedImage(pathname, absPath, refs) {
|
|
|
11315
11127
|
if (!refs.has(imageRefKey(pathname)))
|
|
11316
11128
|
return false;
|
|
11317
11129
|
try {
|
|
11318
|
-
await
|
|
11130
|
+
await stat4(absPath);
|
|
11319
11131
|
return false;
|
|
11320
11132
|
} catch (err) {
|
|
11321
11133
|
return err?.code === "ENOENT";
|
|
@@ -11597,7 +11409,7 @@ async function startPreviewServer(options) {
|
|
|
11597
11409
|
}
|
|
11598
11410
|
|
|
11599
11411
|
// src/lib/project-scaffold.ts
|
|
11600
|
-
import { access, copyFile, cp as cp2, mkdir as mkdir7, readdir as readdir5, readFile as
|
|
11412
|
+
import { access, copyFile, cp as cp2, mkdir as mkdir7, readdir as readdir5, readFile as readFile27, stat as stat5, writeFile as writeFile6 } from "node:fs/promises";
|
|
11601
11413
|
import { constants as FS, existsSync as existsSync12 } from "node:fs";
|
|
11602
11414
|
import path18 from "node:path";
|
|
11603
11415
|
|
|
@@ -11796,7 +11608,7 @@ async function scaffoldProject(options) {
|
|
|
11796
11608
|
async function firstSourceFile(manifestPath) {
|
|
11797
11609
|
let text;
|
|
11798
11610
|
try {
|
|
11799
|
-
text = await
|
|
11611
|
+
text = await readFile27(manifestPath, "utf8");
|
|
11800
11612
|
} catch {
|
|
11801
11613
|
return;
|
|
11802
11614
|
}
|
|
@@ -11808,7 +11620,7 @@ async function firstSourceFile(manifestPath) {
|
|
|
11808
11620
|
return m ? m[1].trim() : undefined;
|
|
11809
11621
|
}
|
|
11810
11622
|
async function fillTemplateFile(filePath, substitutions) {
|
|
11811
|
-
let text = await
|
|
11623
|
+
let text = await readFile27(filePath, "utf8");
|
|
11812
11624
|
for (const [token, value] of Object.entries(substitutions)) {
|
|
11813
11625
|
text = text.split(token).join(value);
|
|
11814
11626
|
}
|
|
@@ -11816,7 +11628,7 @@ async function fillTemplateFile(filePath, substitutions) {
|
|
|
11816
11628
|
}
|
|
11817
11629
|
|
|
11818
11630
|
// src/lib/extension-scaffold.ts
|
|
11819
|
-
import { access as access2, mkdir as mkdir8, readFile as
|
|
11631
|
+
import { access as access2, mkdir as mkdir8, readFile as readFile28, writeFile as writeFile7 } from "node:fs/promises";
|
|
11820
11632
|
import { constants as FS2 } from "node:fs";
|
|
11821
11633
|
import path19 from "node:path";
|
|
11822
11634
|
var EXTENSION_KINDS = ["plugin", "theme"];
|
|
@@ -11933,7 +11745,7 @@ async function scaffoldExtension(options) {
|
|
|
11933
11745
|
const src = await getAssetPath(`extension-templates/${kind}/${assetName}`);
|
|
11934
11746
|
const dest = path19.join(extensionDir, relDest);
|
|
11935
11747
|
await mkdir8(path19.dirname(dest), { recursive: true });
|
|
11936
|
-
const text = await
|
|
11748
|
+
const text = await readFile28(src, "utf8");
|
|
11937
11749
|
const table = relDest.endsWith(".json") ? jsonSafe : plain;
|
|
11938
11750
|
await writeFile7(dest, substitute(text, table), "utf8");
|
|
11939
11751
|
written.push(relDest);
|
|
@@ -11978,7 +11790,7 @@ var SKIP_ENTRIES = new Set([
|
|
|
11978
11790
|
|
|
11979
11791
|
// src/lib/extension-import.ts
|
|
11980
11792
|
import { existsSync as existsSync13 } from "node:fs";
|
|
11981
|
-
import { cp as cp3, mkdir as mkdir9, mkdtemp as mkdtemp2, readFile as
|
|
11793
|
+
import { cp as cp3, mkdir as mkdir9, mkdtemp as mkdtemp2, readFile as readFile29, rm as rm4, writeFile as writeFile8 } from "node:fs/promises";
|
|
11982
11794
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
11983
11795
|
import path20 from "node:path";
|
|
11984
11796
|
import { unzipSync } from "fflate";
|
|
@@ -12051,7 +11863,7 @@ async function finalizeExtensionImport(projectDir, sourceDir, relPaths, fallback
|
|
|
12051
11863
|
if (!existsSync13(cssPath)) {
|
|
12052
11864
|
throw new Error("A theme must contain a theme.css file.");
|
|
12053
11865
|
}
|
|
12054
|
-
const css = await
|
|
11866
|
+
const css = await readFile29(cssPath, "utf8");
|
|
12055
11867
|
const { reject, warnings: printFindings } = classifyThemeCssFindings(checkCss(css, "theme.css"));
|
|
12056
11868
|
if (reject) {
|
|
12057
11869
|
throw new Error(`theme.css could not be parsed — ${reject.message}`);
|
|
@@ -12079,7 +11891,7 @@ async function finalizeExtensionImport(projectDir, sourceDir, relPaths, fallback
|
|
|
12079
11891
|
for (let i = 0;i < extraSheets.length; i++) {
|
|
12080
11892
|
const rel = extraSheets[i];
|
|
12081
11893
|
const sheetPath = extraSheetPaths[i];
|
|
12082
|
-
const sheetCss = await
|
|
11894
|
+
const sheetCss = await readFile29(sheetPath, "utf8");
|
|
12083
11895
|
const { reject: sheetReject, warnings: sheetFindings } = classifyThemeCssFindings(checkCss(sheetCss, rel));
|
|
12084
11896
|
if (sheetReject) {
|
|
12085
11897
|
throw new Error(`${rel} could not be parsed — ${sheetReject.message}`);
|
|
@@ -12112,7 +11924,7 @@ async function completeLandedManifest(dest, id, meta, metaExists) {
|
|
|
12112
11924
|
let pkg = {};
|
|
12113
11925
|
if (metaExists) {
|
|
12114
11926
|
try {
|
|
12115
|
-
const parsed = JSON.parse(await
|
|
11927
|
+
const parsed = JSON.parse(await readFile29(file, "utf8"));
|
|
12116
11928
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
12117
11929
|
pkg = parsed;
|
|
12118
11930
|
}
|
|
@@ -12214,11 +12026,11 @@ async function importExtensionFromCssText(projectDir, css, name) {
|
|
|
12214
12026
|
async function importExtensionFromFile(projectDir, filePath) {
|
|
12215
12027
|
const ext = path20.extname(filePath).toLowerCase();
|
|
12216
12028
|
if (ext === ".zip") {
|
|
12217
|
-
const buf = await
|
|
12029
|
+
const buf = await readFile29(filePath);
|
|
12218
12030
|
return importExtensionFromZip(projectDir, new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength));
|
|
12219
12031
|
}
|
|
12220
12032
|
if (ext === ".css") {
|
|
12221
|
-
const css = await
|
|
12033
|
+
const css = await readFile29(filePath, "utf8");
|
|
12222
12034
|
return importExtensionFromCssText(projectDir, css, prettify(path20.basename(filePath, ".css")));
|
|
12223
12035
|
}
|
|
12224
12036
|
throw new Error("Choose a .zip extension package or a .css stylesheet.");
|
|
@@ -13002,7 +12814,7 @@ var drivethrurpgProvider = {
|
|
|
13002
12814
|
};
|
|
13003
12815
|
|
|
13004
12816
|
// src/lib/publish/providers/gdrive.ts
|
|
13005
|
-
import { mkdtemp as mkdtemp3, readFile as
|
|
12817
|
+
import { mkdtemp as mkdtemp3, readFile as readFile30, readdir as readdir6, rm as rm5, stat as stat6, writeFile as writeFile10 } from "node:fs/promises";
|
|
13006
12818
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
13007
12819
|
import path22 from "node:path";
|
|
13008
12820
|
import { Zip, ZipDeflate } from "fflate";
|
|
@@ -13394,12 +13206,12 @@ async function collectZipEntries(root, dir, out, onWarn) {
|
|
|
13394
13206
|
await collectZipEntries(root, full, out, onWarn);
|
|
13395
13207
|
} else if (entry.isFile()) {
|
|
13396
13208
|
const rel = path22.relative(root, full).split(path22.sep).join("/");
|
|
13397
|
-
out[rel] = await
|
|
13209
|
+
out[rel] = await readFile30(full);
|
|
13398
13210
|
} else if (entry.isSymbolicLink()) {
|
|
13399
|
-
const resolved = await
|
|
13211
|
+
const resolved = await stat6(full).catch(() => null);
|
|
13400
13212
|
if (resolved?.isFile()) {
|
|
13401
13213
|
const rel = path22.relative(root, full).split(path22.sep).join("/");
|
|
13402
|
-
out[rel] = await
|
|
13214
|
+
out[rel] = await readFile30(full);
|
|
13403
13215
|
} else if (resolved?.isDirectory()) {
|
|
13404
13216
|
await collectZipEntries(root, full, out, onWarn);
|
|
13405
13217
|
} else {
|
|
@@ -13469,7 +13281,7 @@ var gdriveProvider = {
|
|
|
13469
13281
|
cleanup: async () => {}
|
|
13470
13282
|
};
|
|
13471
13283
|
try {
|
|
13472
|
-
const artifactStat = await
|
|
13284
|
+
const artifactStat = await stat6(source.filePath);
|
|
13473
13285
|
const about = await driveAbout(fetchImpl, accessToken);
|
|
13474
13286
|
if (about.quota.limitBytes != null && about.quota.freeBytes != null) {
|
|
13475
13287
|
if (artifactStat.size > about.quota.freeBytes) {
|
|
@@ -13514,7 +13326,7 @@ var gdriveProvider = {
|
|
|
13514
13326
|
};
|
|
13515
13327
|
|
|
13516
13328
|
// src/lib/publish/butler.ts
|
|
13517
|
-
import { chmod, mkdir as mkdir11, stat as
|
|
13329
|
+
import { chmod, mkdir as mkdir11, stat as stat7, writeFile as writeFile11 } from "node:fs/promises";
|
|
13518
13330
|
import path23 from "node:path";
|
|
13519
13331
|
import { unzipSync as unzipSync2 } from "fflate";
|
|
13520
13332
|
var BUTLER_DOWNLOAD_TIMEOUT_MS = 300000;
|
|
@@ -13535,7 +13347,7 @@ function butlerBinaryName(platform = process.platform) {
|
|
|
13535
13347
|
}
|
|
13536
13348
|
async function fileExists2(p) {
|
|
13537
13349
|
try {
|
|
13538
|
-
return (await
|
|
13350
|
+
return (await stat7(p)).isFile();
|
|
13539
13351
|
} catch {
|
|
13540
13352
|
return false;
|
|
13541
13353
|
}
|
|
@@ -13778,7 +13590,7 @@ var kdpProvider = {
|
|
|
13778
13590
|
};
|
|
13779
13591
|
|
|
13780
13592
|
// src/lib/publish/providers/local-folder.ts
|
|
13781
|
-
import { cp as cp4, mkdir as mkdir12, stat as
|
|
13593
|
+
import { cp as cp4, mkdir as mkdir12, stat as stat8 } from "node:fs/promises";
|
|
13782
13594
|
import path24 from "node:path";
|
|
13783
13595
|
var LOCAL_PUBLISH_DEFAULT_DIR = "dist";
|
|
13784
13596
|
var info8 = {
|
|
@@ -13805,7 +13617,7 @@ var localFolderProvider = {
|
|
|
13805
13617
|
async preflight(req) {
|
|
13806
13618
|
const dir = localPublishDir(req);
|
|
13807
13619
|
try {
|
|
13808
|
-
const s = await
|
|
13620
|
+
const s = await stat8(dir);
|
|
13809
13621
|
if (!s.isDirectory()) {
|
|
13810
13622
|
return [
|
|
13811
13623
|
{ severity: "error", id: "local/not-a-folder", message: `${dir} exists but is not a folder.` }
|
|
@@ -14060,7 +13872,7 @@ function publishProviderFor(id) {
|
|
|
14060
13872
|
}
|
|
14061
13873
|
|
|
14062
13874
|
// src/lib/publish/run-publish.ts
|
|
14063
|
-
import { readdir as readdir7, stat as
|
|
13875
|
+
import { readdir as readdir7, stat as stat9 } from "node:fs/promises";
|
|
14064
13876
|
import path25 from "node:path";
|
|
14065
13877
|
function resolvePublishFormat(info10, providerConfig) {
|
|
14066
13878
|
if (info10.formats && info10.formats.length > 0) {
|
|
@@ -14102,7 +13914,7 @@ var PDF_HINT = "Build the PDF first (gutterpress build, or export it from the ap
|
|
|
14102
13914
|
var HTML_HINT = "Build the website export first (gutterpress build --format html).";
|
|
14103
13915
|
async function artifactIssues(artifact) {
|
|
14104
13916
|
try {
|
|
14105
|
-
const s = await
|
|
13917
|
+
const s = await stat9(artifact.path);
|
|
14106
13918
|
if (artifact.format === "pdf" && !s.isFile()) {
|
|
14107
13919
|
return [
|
|
14108
13920
|
{
|
|
@@ -14148,7 +13960,7 @@ async function artifactIssues(artifact) {
|
|
|
14148
13960
|
var BUILD_FINGERPRINT_FILENAME = "build-fingerprint.json";
|
|
14149
13961
|
async function htmlDirIssues(dir) {
|
|
14150
13962
|
const issues = [];
|
|
14151
|
-
const isThere = async (rel) =>
|
|
13963
|
+
const isThere = async (rel) => stat9(path25.join(dir, rel)).then(() => true, () => false);
|
|
14152
13964
|
if (!await isThere(BOOK_HTML)) {
|
|
14153
13965
|
issues.push({
|
|
14154
13966
|
severity: "error",
|
|
@@ -14386,7 +14198,7 @@ import git8 from "isomorphic-git";
|
|
|
14386
14198
|
// src/lib/remote-auth/scorched-earth.ts
|
|
14387
14199
|
import git9 from "isomorphic-git";
|
|
14388
14200
|
// src/lib/publish/selections.ts
|
|
14389
|
-
import { chmod as chmod2, mkdir as mkdir13, readFile as
|
|
14201
|
+
import { chmod as chmod2, mkdir as mkdir13, readFile as readFile31, writeFile as writeFile12 } from "node:fs/promises";
|
|
14390
14202
|
import path26 from "node:path";
|
|
14391
14203
|
class PublishSelectionsStore {
|
|
14392
14204
|
filePath;
|
|
@@ -14396,7 +14208,7 @@ class PublishSelectionsStore {
|
|
|
14396
14208
|
}
|
|
14397
14209
|
async read() {
|
|
14398
14210
|
try {
|
|
14399
|
-
const raw = await
|
|
14211
|
+
const raw = await readFile31(this.filePath, "utf8");
|
|
14400
14212
|
const parsed = JSON.parse(raw);
|
|
14401
14213
|
if (parsed && typeof parsed === "object") {
|
|
14402
14214
|
return {
|