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
|
@@ -9,7 +9,20 @@ import {
|
|
|
9
9
|
getAssetsDir,
|
|
10
10
|
lastPageMode,
|
|
11
11
|
parseSize
|
|
12
|
-
} from "./index-
|
|
12
|
+
} from "./index-gm5xbx5w.js";
|
|
13
|
+
import {
|
|
14
|
+
countLinkAnnotations,
|
|
15
|
+
getImageResolutions,
|
|
16
|
+
getOpPass,
|
|
17
|
+
getOutlineCount,
|
|
18
|
+
getPageLabels,
|
|
19
|
+
getPageSize,
|
|
20
|
+
getTextPass,
|
|
21
|
+
isLoadable,
|
|
22
|
+
loadPdf,
|
|
23
|
+
pageHasMarks,
|
|
24
|
+
retainPdfCache
|
|
25
|
+
} from "./index-sth219v1.js";
|
|
13
26
|
import {
|
|
14
27
|
INSTALL_HINTS,
|
|
15
28
|
enhancedPath,
|
|
@@ -157,6 +170,8 @@ var DTRPG_PRESET = {
|
|
|
157
170
|
icc: "profiles/CGATS21_CRPC1.icc",
|
|
158
171
|
stripAnnotations: true,
|
|
159
172
|
blackText: "k-only",
|
|
173
|
+
transparency: "flatten-page",
|
|
174
|
+
flattenPages: [],
|
|
160
175
|
rasterDpi: undefined
|
|
161
176
|
},
|
|
162
177
|
page: {
|
|
@@ -242,6 +257,8 @@ var BOOK_PRESET = {
|
|
|
242
257
|
icc: "profiles/CGATS21_CRPC1.icc",
|
|
243
258
|
stripAnnotations: true,
|
|
244
259
|
blackText: "icc",
|
|
260
|
+
transparency: "flatten-page",
|
|
261
|
+
flattenPages: [],
|
|
245
262
|
rasterDpi: undefined
|
|
246
263
|
},
|
|
247
264
|
page: {
|
|
@@ -647,6 +664,14 @@ function resolveWithPreset(cliOverrides, manifest, preset) {
|
|
|
647
664
|
if (lastPage !== undefined && lastPage !== "blank" && lastPage !== "short-by-one") {
|
|
648
665
|
throw new UsageError(`Manifest field \`print.lastPage\` must be "blank" or "short-by-one", got ${JSON.stringify(lastPage)}.`);
|
|
649
666
|
}
|
|
667
|
+
const transparency = c.pdfx?.transparency ?? m.pdfx?.transparency;
|
|
668
|
+
if (transparency !== undefined && transparency !== "flatten-page" && transparency !== "preserve-text") {
|
|
669
|
+
throw new UsageError(`Manifest field \`pdfx.transparency\` must be "flatten-page" or "preserve-text", got ${JSON.stringify(transparency)}.`);
|
|
670
|
+
}
|
|
671
|
+
const flattenPages = c.pdfx?.flattenPages ?? m.pdfx?.flattenPages;
|
|
672
|
+
if (flattenPages !== undefined && !(Array.isArray(flattenPages) && flattenPages.every((n) => Number.isInteger(n) && n >= 1))) {
|
|
673
|
+
throw new UsageError(`Manifest field \`pdfx.flattenPages\` must be a list of page numbers (1, 2, …), got ${JSON.stringify(flattenPages)}.`);
|
|
674
|
+
}
|
|
650
675
|
const rasterDpi = c.pdfx?.rasterDpi ?? m.pdfx?.rasterDpi;
|
|
651
676
|
if (rasterDpi !== undefined && !(Number.isInteger(rasterDpi) && rasterDpi >= 72 && rasterDpi <= 1200)) {
|
|
652
677
|
throw new UsageError(`Manifest field \`pdfx.rasterDpi\` must be a whole number from 72 to 1200, got ${JSON.stringify(rasterDpi)}.`);
|
|
@@ -1964,7 +1989,9 @@ var GUTTERPRESS_CSS = `
|
|
|
1964
1989
|
cap at equal specificity */
|
|
1965
1990
|
.gp-small { width: 25%; max-width: 100%; }
|
|
1966
1991
|
.gp-medium { width: 50%; max-width: 100%; }
|
|
1967
|
-
.gp-large { width:
|
|
1992
|
+
.gp-large { width: 60%; max-width: 100%; }
|
|
1993
|
+
.gp-xl { width: 80%; max-width: 100%; }
|
|
1994
|
+
.gp-xxl { width: 90%; max-width: 100%; }
|
|
1968
1995
|
|
|
1969
1996
|
/* float clearance presets — consumed by var(--gp-gap) in the float rules
|
|
1970
1997
|
above and by .gp-shape's shape-margin below; --gp-gap itself is
|
|
@@ -2022,10 +2049,16 @@ img.gp-shape {
|
|
|
2022
2049
|
}
|
|
2023
2050
|
|
|
2024
2051
|
/* pin — within the nearest positioned ancestor (.page/.spread, rule above).
|
|
2025
|
-
|
|
2052
|
+
The four insets are the pin box: 0 (the text block's edge) unless an
|
|
2053
|
+
engine set --gp-pin-<edge> on the page root for an edge a pin uses (the
|
|
2054
|
+
art-safe line). Non-auto insets and the explicit centers are
|
|
2055
|
+
load-bearing; see doctrine comment. */
|
|
2026
2056
|
.gp-pin {
|
|
2027
2057
|
position: absolute;
|
|
2028
|
-
|
|
2058
|
+
top: var(--gp-pin-top, 0px);
|
|
2059
|
+
right: var(--gp-pin-right, 0px);
|
|
2060
|
+
bottom: var(--gp-pin-bottom, 0px);
|
|
2061
|
+
left: var(--gp-pin-left, 0px);
|
|
2029
2062
|
align-self: center;
|
|
2030
2063
|
justify-self: center;
|
|
2031
2064
|
margin: 0;
|
|
@@ -2040,6 +2073,16 @@ img.gp-shape {
|
|
|
2040
2073
|
.gp-left { justify-self: start; }
|
|
2041
2074
|
.gp-right { justify-self: end; }
|
|
2042
2075
|
|
|
2076
|
+
/* the escape hatch — the paper's edge, past the printer's safe area: the
|
|
2077
|
+
pin box loses its art-safe insets. Set on the pin itself, so it beats the
|
|
2078
|
+
values the page root hands down. */
|
|
2079
|
+
.gp-pin.gp-flush {
|
|
2080
|
+
--gp-pin-top: 0px;
|
|
2081
|
+
--gp-pin-right: 0px;
|
|
2082
|
+
--gp-pin-bottom: 0px;
|
|
2083
|
+
--gp-pin-left: 0px;
|
|
2084
|
+
}
|
|
2085
|
+
|
|
2043
2086
|
/* wrapper-margin neutralization (same pattern and rationale as the
|
|
2044
2087
|
.gp-bleed paragraph-margin note in the doctrine comment; for pin, the
|
|
2045
2088
|
emptied paragraph would otherwise leave a phantom margin gap in flow) */
|
|
@@ -2149,6 +2192,8 @@ var GP_CLASSES = new Set([
|
|
|
2149
2192
|
"gp-small",
|
|
2150
2193
|
"gp-medium",
|
|
2151
2194
|
"gp-large",
|
|
2195
|
+
"gp-xl",
|
|
2196
|
+
"gp-xxl",
|
|
2152
2197
|
"gp-tight",
|
|
2153
2198
|
"gp-loose",
|
|
2154
2199
|
"gp-columns",
|
|
@@ -2165,6 +2210,7 @@ var GP_CLASSES = new Set([
|
|
|
2165
2210
|
"gp-pin",
|
|
2166
2211
|
"gp-top",
|
|
2167
2212
|
"gp-bottom",
|
|
2213
|
+
"gp-flush",
|
|
2168
2214
|
"gp-behind",
|
|
2169
2215
|
"gp-base",
|
|
2170
2216
|
"gp-raised",
|
|
@@ -2178,8 +2224,7 @@ var GP_CLASSES = new Set([
|
|
|
2178
2224
|
"gp-alert-caution",
|
|
2179
2225
|
"gp-page-break",
|
|
2180
2226
|
"gp-column-break",
|
|
2181
|
-
"gp-continued"
|
|
2182
|
-
"gp-flush"
|
|
2227
|
+
"gp-continued"
|
|
2183
2228
|
]);
|
|
2184
2229
|
|
|
2185
2230
|
// src/lib/markdown/table-align.ts
|
|
@@ -2306,6 +2351,21 @@ function hasPinClass(token) {
|
|
|
2306
2351
|
const cls = token.attrGet && token.attrGet("class");
|
|
2307
2352
|
return typeof cls === "string" && cls.split(/\s+/).includes("gp-pin");
|
|
2308
2353
|
}
|
|
2354
|
+
var PIN_EDGES = ["gp-top", "gp-right", "gp-bottom", "gp-left"];
|
|
2355
|
+
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.";
|
|
2356
|
+
function checkFlushArt(token, env, line) {
|
|
2357
|
+
if (token.type !== "image")
|
|
2358
|
+
return;
|
|
2359
|
+
const cls = token.attrGet && token.attrGet("class");
|
|
2360
|
+
if (typeof cls !== "string")
|
|
2361
|
+
return;
|
|
2362
|
+
const classes = cls.split(/\s+/);
|
|
2363
|
+
if (!classes.includes("gp-pin") || !classes.includes("gp-flush"))
|
|
2364
|
+
return;
|
|
2365
|
+
if (!classes.some((c) => PIN_EDGES.includes(c)))
|
|
2366
|
+
return;
|
|
2367
|
+
warn3(env, line, "flush_art", FLUSH_ART_MSG);
|
|
2368
|
+
}
|
|
2309
2369
|
function elementNameFor(token) {
|
|
2310
2370
|
switch (token.type) {
|
|
2311
2371
|
case "layout_chapter_open":
|
|
@@ -2365,6 +2425,7 @@ function gpPinScope(md) {
|
|
|
2365
2425
|
if (token.type === "inline" && token.children) {
|
|
2366
2426
|
for (const child of token.children) {
|
|
2367
2427
|
checkUnknownGpClasses(child, state.env, line);
|
|
2428
|
+
checkFlushArt(child, state.env, line);
|
|
2368
2429
|
}
|
|
2369
2430
|
}
|
|
2370
2431
|
}
|
|
@@ -3116,6 +3177,20 @@ function layerSlug(name) {
|
|
|
3116
3177
|
return /^[a-z]/.test(slug) ? slug : `x${slug}`;
|
|
3117
3178
|
}
|
|
3118
3179
|
|
|
3180
|
+
// src/engine/shared/print-area.ts
|
|
3181
|
+
function printAreaMeta(page) {
|
|
3182
|
+
const area = JSON.stringify({
|
|
3183
|
+
width: page.width,
|
|
3184
|
+
height: page.height,
|
|
3185
|
+
bleed: page.bleed ?? 0,
|
|
3186
|
+
safe: page.safe ?? 0,
|
|
3187
|
+
artSafe: page.artSafe,
|
|
3188
|
+
preset: page.preset,
|
|
3189
|
+
spec: page.spec
|
|
3190
|
+
});
|
|
3191
|
+
return `<meta name="gp-print-area" content='${area.replace(/&/g, "&").replace(/'/g, "'")}'>`;
|
|
3192
|
+
}
|
|
3193
|
+
|
|
3119
3194
|
// src/lib/markdown/assemble.ts
|
|
3120
3195
|
async function assembleBookHtml(opts) {
|
|
3121
3196
|
const title = opts.title ?? "Document";
|
|
@@ -3181,7 +3256,8 @@ ${projectCss.trim()}` : null
|
|
|
3181
3256
|
<html lang="en"${printAttrs}>
|
|
3182
3257
|
<head>
|
|
3183
3258
|
<meta charset="UTF-8">
|
|
3184
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0"
|
|
3259
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">${opts.printArea ? `
|
|
3260
|
+
${printAreaMeta(opts.printArea)}` : ""}
|
|
3185
3261
|
<title>${title}</title>${preloadTags}
|
|
3186
3262
|
<style data-project-css>
|
|
3187
3263
|
${inlineCss}
|
|
@@ -3638,6 +3714,7 @@ ${css.trim()}
|
|
|
3638
3714
|
preloadImages: cssAssetCopies.map((c) => c.to),
|
|
3639
3715
|
title: opts.title,
|
|
3640
3716
|
print: opts.print,
|
|
3717
|
+
printArea: opts.printArea,
|
|
3641
3718
|
plugins: opts.plugins,
|
|
3642
3719
|
pluginCss,
|
|
3643
3720
|
annotateSourceChapters: opts.annotateSourceChapters,
|
|
@@ -3650,6 +3727,7 @@ async function renderChaptersToFile(inputDir, outDir, opts = {}) {
|
|
|
3650
3727
|
const html = await renderChapters(inputDir, {
|
|
3651
3728
|
title: opts.title,
|
|
3652
3729
|
print: opts.print,
|
|
3730
|
+
printArea: opts.printArea,
|
|
3653
3731
|
styles: opts.styles,
|
|
3654
3732
|
files: opts.files,
|
|
3655
3733
|
plugins: opts.plugins,
|
|
@@ -3731,6 +3809,118 @@ function resolveDeclaredStyles(rawStyles, baseDir, subject) {
|
|
|
3731
3809
|
// src/lib/extension-manifest.ts
|
|
3732
3810
|
import { readFile as readFile4 } from "node:fs/promises";
|
|
3733
3811
|
import path3 from "node:path";
|
|
3812
|
+
import { satisfies, validRange } from "semver";
|
|
3813
|
+
// package.json
|
|
3814
|
+
var package_default = {
|
|
3815
|
+
name: "gutterpress",
|
|
3816
|
+
version: "0.11.20-alpha.4",
|
|
3817
|
+
description: "Markdown-to-PDF converter for professional print layout using a native Chromium print engine and Ghostscript.",
|
|
3818
|
+
author: "itlackey",
|
|
3819
|
+
license: "MPL-2.0",
|
|
3820
|
+
keywords: [
|
|
3821
|
+
"markdown",
|
|
3822
|
+
"pdf",
|
|
3823
|
+
"print",
|
|
3824
|
+
"ghostscript",
|
|
3825
|
+
"book",
|
|
3826
|
+
"publishing",
|
|
3827
|
+
"zine"
|
|
3828
|
+
],
|
|
3829
|
+
repository: {
|
|
3830
|
+
type: "git",
|
|
3831
|
+
url: "https://github.com/dimm-city/gutterpress.git"
|
|
3832
|
+
},
|
|
3833
|
+
homepage: "https://github.com/dimm-city/gutterpress#readme",
|
|
3834
|
+
bugs: {
|
|
3835
|
+
url: "https://github.com/dimm-city/gutterpress/issues"
|
|
3836
|
+
},
|
|
3837
|
+
type: "module",
|
|
3838
|
+
main: "./dist/index.js",
|
|
3839
|
+
types: "./dist/index.d.ts",
|
|
3840
|
+
bin: {
|
|
3841
|
+
gutterpress: "./dist/cli.js"
|
|
3842
|
+
},
|
|
3843
|
+
exports: {
|
|
3844
|
+
".": {
|
|
3845
|
+
types: "./dist/index.d.ts",
|
|
3846
|
+
default: "./dist/index.js"
|
|
3847
|
+
},
|
|
3848
|
+
"./api": {
|
|
3849
|
+
types: "./dist/api/index.d.ts",
|
|
3850
|
+
default: "./dist/api/index.js"
|
|
3851
|
+
},
|
|
3852
|
+
"./render": {
|
|
3853
|
+
types: "./dist/render.d.ts",
|
|
3854
|
+
default: "./dist/render.js"
|
|
3855
|
+
}
|
|
3856
|
+
},
|
|
3857
|
+
files: [
|
|
3858
|
+
"dist/",
|
|
3859
|
+
"README.md",
|
|
3860
|
+
"LICENSE"
|
|
3861
|
+
],
|
|
3862
|
+
scripts: {
|
|
3863
|
+
"build:library": "bun scripts/build-engine-bundles.mjs && rimraf dist && bun build src/index.ts src/api/index.ts --target=node --packages=external --splitting --outdir=dist && bun build src/render.ts --target=node --packages=external --outdir=dist && node scripts/check-render-pure.mjs && tsc -p tsconfig.build.json",
|
|
3864
|
+
build: "bun run build:library && bun build src/cli.ts --target=node --packages=external --splitting --outdir=dist",
|
|
3865
|
+
prepublishOnly: "bun run build",
|
|
3866
|
+
test: "bun test",
|
|
3867
|
+
typecheck: "tsc --noEmit",
|
|
3868
|
+
"typecheck:engine-browser": "tsc --noEmit -p src/engine/browser.tsconfig.json",
|
|
3869
|
+
"parity:gate": "bun scripts/native-parity-gate.ts"
|
|
3870
|
+
},
|
|
3871
|
+
engines: {
|
|
3872
|
+
bun: ">=1.0.0",
|
|
3873
|
+
node: ">=22.0.0"
|
|
3874
|
+
},
|
|
3875
|
+
dependencies: {
|
|
3876
|
+
chokidar: "^5.0.0",
|
|
3877
|
+
citty: "^0.2.0",
|
|
3878
|
+
diff3: "0.0.3",
|
|
3879
|
+
fflate: "0.8.3",
|
|
3880
|
+
glob: "^13.0.0",
|
|
3881
|
+
htmlhint: "^1.9.2",
|
|
3882
|
+
ignore: "^5.3.2",
|
|
3883
|
+
"isomorphic-git": "^1.38.4",
|
|
3884
|
+
"markdown-it": "^14.3.2",
|
|
3885
|
+
"markdown-it-abbr": "^2.0.0",
|
|
3886
|
+
"markdown-it-attrs": "^4.3.0",
|
|
3887
|
+
"markdown-it-deflist": "^3.0.1",
|
|
3888
|
+
"markdown-it-footnote": "^4.0.0",
|
|
3889
|
+
"markdown-it-mark": "^4.0.0",
|
|
3890
|
+
"markdown-it-source-map": "^0.1.1",
|
|
3891
|
+
"markdown-it-sub": "^2.0.0",
|
|
3892
|
+
"markdown-it-sup": "^2.0.0",
|
|
3893
|
+
markdownlint: "^0.40.0",
|
|
3894
|
+
"pdf-lib": "^1.17.1",
|
|
3895
|
+
postcss: "^8.5.18",
|
|
3896
|
+
"resolve.exports": "2.0.3",
|
|
3897
|
+
semver: "7.8.0",
|
|
3898
|
+
tar: "7.5.22",
|
|
3899
|
+
unpdf: "^1.6.2",
|
|
3900
|
+
ws: "^8.21.0",
|
|
3901
|
+
yaml: "^2.8.2"
|
|
3902
|
+
},
|
|
3903
|
+
devDependencies: {
|
|
3904
|
+
"@types/bun": "1.3.14",
|
|
3905
|
+
"@types/markdown-it": "^14.1.2",
|
|
3906
|
+
"@types/node": "^22.0.0",
|
|
3907
|
+
"@types/semver": "^7.7.1",
|
|
3908
|
+
"@types/ws": "^8.5.13",
|
|
3909
|
+
playwright: "^1.60.0",
|
|
3910
|
+
rimraf: "^6.0.0",
|
|
3911
|
+
typescript: "^5"
|
|
3912
|
+
}
|
|
3913
|
+
};
|
|
3914
|
+
|
|
3915
|
+
// src/lib/version.ts
|
|
3916
|
+
var PACKAGE_META = {
|
|
3917
|
+
version: package_default.version ?? "unknown",
|
|
3918
|
+
dependencies: package_default.dependencies ?? {},
|
|
3919
|
+
devDependencies: package_default.devDependencies ?? {}
|
|
3920
|
+
};
|
|
3921
|
+
var PACKAGE_VERSION = PACKAGE_META.version;
|
|
3922
|
+
|
|
3923
|
+
// src/lib/extension-manifest.ts
|
|
3734
3924
|
var EXTENSION_MANIFEST_FILENAME = "package.json";
|
|
3735
3925
|
var GUTTERPRESS_KEY = "gutterpress";
|
|
3736
3926
|
function object(value) {
|
|
@@ -3754,6 +3944,7 @@ function metaFromPackageJson(raw) {
|
|
|
3754
3944
|
...str(pkg.description) ? { description: str(pkg.description) } : {},
|
|
3755
3945
|
...keywords ? { keywords } : {},
|
|
3756
3946
|
...str(pkg.main) ? { main: str(pkg.main) } : {},
|
|
3947
|
+
...str(object(pkg.engines)?.gutterpress) ? { gutterpressRange: str(object(pkg.engines)?.gutterpress) } : {},
|
|
3757
3948
|
..."preview" in gp ? { preview: str(gp.preview) ?? null } : {},
|
|
3758
3949
|
...Array.isArray(gp.styles) ? { styles: declaredList(gp.styles) } : {},
|
|
3759
3950
|
...str(gp.tokensFile) ? { tokensFile: str(gp.tokensFile) } : {},
|
|
@@ -3790,6 +3981,17 @@ function extensionCarries(meta) {
|
|
|
3790
3981
|
function pathEscapesFolder(rel) {
|
|
3791
3982
|
return path3.isAbsolute(rel) || rel.split(/[\\/]/).includes("..");
|
|
3792
3983
|
}
|
|
3984
|
+
function assertSupportsThisGutterpress(meta, ref) {
|
|
3985
|
+
const range = meta.gutterpressRange;
|
|
3986
|
+
if (range === undefined)
|
|
3987
|
+
return;
|
|
3988
|
+
if (!validRange(range)) {
|
|
3989
|
+
throw new Error(`Extension "${ref}" has an invalid engines.gutterpress range "${range}".`);
|
|
3990
|
+
}
|
|
3991
|
+
if (!satisfies(PACKAGE_VERSION, range, { includePrerelease: true })) {
|
|
3992
|
+
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.`);
|
|
3993
|
+
}
|
|
3994
|
+
}
|
|
3793
3995
|
function assertExtensionContained(meta) {
|
|
3794
3996
|
if (meta.engineStyles !== undefined) {
|
|
3795
3997
|
throw new Error("The extension's metadata declares `engineStyles`, which was removed — " + "move its entries to the end of `styles`.");
|
|
@@ -4078,6 +4280,7 @@ This folder still has a ${stale}. Gutterpress no longer reads it — ` + `descri
|
|
|
4078
4280
|
async function loadExtensionFromDir(extensionDir, config, pluginRef) {
|
|
4079
4281
|
const meta = await readExtensionMeta(extensionDir);
|
|
4080
4282
|
assertExtensionContained(meta);
|
|
4283
|
+
assertSupportsThisGutterpress(meta, pluginRef);
|
|
4081
4284
|
const resolved = resolveExtension(extensionDir, meta, `Plugin "${pluginRef}"`);
|
|
4082
4285
|
const extensionStyles = resolved.styles ?? [];
|
|
4083
4286
|
const name = config.name ?? meta.name ?? pluginRef;
|
|
@@ -4152,6 +4355,7 @@ async function loadPlugin(config, baseDir) {
|
|
|
4152
4355
|
if (loaded.packageDir) {
|
|
4153
4356
|
const meta = await readExtensionMeta(loaded.packageDir);
|
|
4154
4357
|
assertExtensionContained(meta);
|
|
4358
|
+
assertSupportsThisGutterpress(meta, pluginRef);
|
|
4155
4359
|
const resolved = resolveExtension(loaded.packageDir, { ...meta, main: undefined }, `Plugin "${pluginRef}"`);
|
|
4156
4360
|
if (resolved.markdown && loaded.entryPath && resolve3(resolved.markdown) !== resolve3(loaded.entryPath)) {
|
|
4157
4361
|
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.");
|
|
@@ -4282,7 +4486,7 @@ import path5 from "node:path";
|
|
|
4282
4486
|
import { Transform } from "node:stream";
|
|
4283
4487
|
import { pipeline } from "node:stream/promises";
|
|
4284
4488
|
import { createGunzip } from "node:zlib";
|
|
4285
|
-
import { maxSatisfying, satisfies, validRange } from "semver";
|
|
4489
|
+
import { maxSatisfying, satisfies as satisfies2, validRange as validRange2 } from "semver";
|
|
4286
4490
|
|
|
4287
4491
|
// src/lib/npm-registry.ts
|
|
4288
4492
|
var DEFAULT_NPM_REGISTRY = "https://registry.npmjs.org";
|
|
@@ -4490,7 +4694,7 @@ async function selectPackage(ctx, name, selector) {
|
|
|
4490
4694
|
version = selector;
|
|
4491
4695
|
} else if (typeof tags[selector] === "string") {
|
|
4492
4696
|
version = tags[selector];
|
|
4493
|
-
} else if (
|
|
4697
|
+
} else if (validRange2(selector)) {
|
|
4494
4698
|
version = maxSatisfying(Object.keys(versions), selector) ?? undefined;
|
|
4495
4699
|
}
|
|
4496
4700
|
if (!version || !isExactNpmVersion(version)) {
|
|
@@ -4708,7 +4912,7 @@ async function installPackage(ctx, name, selector, parentPackagePath, ancestors,
|
|
|
4708
4912
|
}
|
|
4709
4913
|
throw error2;
|
|
4710
4914
|
}
|
|
4711
|
-
const ancestor = ancestors.find((candidate) => candidate.name === name && (candidate.version === selected.version || (selector ?
|
|
4915
|
+
const ancestor = ancestors.find((candidate) => candidate.name === name && (candidate.version === selected.version || (selector ? satisfies2(candidate.version, selector) : false)));
|
|
4712
4916
|
if (ancestor)
|
|
4713
4917
|
return { path: ancestor.path };
|
|
4714
4918
|
if (ctx.records.length >= ctx.limits.totalPackages) {
|
|
@@ -5767,8 +5971,8 @@ async function resolveGhostscript(targetPlatform = process.platform, env = proce
|
|
|
5767
5971
|
}
|
|
5768
5972
|
return targetPlatform === "win32" ? findWindowsGhostscriptInstall(env) : undefined;
|
|
5769
5973
|
}
|
|
5770
|
-
async function
|
|
5771
|
-
const { PDFDocument, PDFDict, PDFName, PDFNumber, PDFRawStream, PDFRef } = await import("pdf-lib");
|
|
5974
|
+
async function transparentPages(pdfBytes) {
|
|
5975
|
+
const { PDFDocument, PDFDict, PDFName, PDFNumber, PDFRawStream, PDFArray, PDFRef } = await import("pdf-lib");
|
|
5772
5976
|
let doc;
|
|
5773
5977
|
try {
|
|
5774
5978
|
doc = await PDFDocument.load(pdfBytes, {
|
|
@@ -5776,36 +5980,64 @@ async function hasLiveTransparency(pdfBytes) {
|
|
|
5776
5980
|
throwOnInvalidObject: false
|
|
5777
5981
|
});
|
|
5778
5982
|
} catch {
|
|
5779
|
-
return
|
|
5983
|
+
return [];
|
|
5780
5984
|
}
|
|
5781
5985
|
const ctx = doc.context;
|
|
5782
|
-
const
|
|
5783
|
-
|
|
5784
|
-
|
|
5785
|
-
if (!dict)
|
|
5786
|
-
continue;
|
|
5986
|
+
const SKIP = new Set(["Parent", "Font", "Annots"]);
|
|
5987
|
+
const isSet = (v) => v !== undefined && String(v) !== "/None";
|
|
5988
|
+
const dictHasTransparency = (dict) => {
|
|
5787
5989
|
const smask = dict.get(PDFName.of("SMask"));
|
|
5788
5990
|
const subtype = String(dict.get(PDFName.of("Subtype")) ?? "");
|
|
5789
5991
|
const type = String(dict.get(PDFName.of("Type")) ?? "");
|
|
5790
|
-
if (subtype === "/Image" &&
|
|
5992
|
+
if (subtype === "/Image" && isSet(smask))
|
|
5791
5993
|
return true;
|
|
5792
|
-
if (type === "/ExtGState") {
|
|
5793
|
-
if (
|
|
5994
|
+
if (type === "/ExtGState" || dict.has(PDFName.of("ca")) || dict.has(PDFName.of("BM"))) {
|
|
5995
|
+
if (isSet(smask))
|
|
5794
5996
|
return true;
|
|
5795
5997
|
for (const key of ["ca", "CA"]) {
|
|
5796
|
-
const alpha = dict.get(PDFName.of(key));
|
|
5998
|
+
const alpha = ctx.lookup(dict.get(PDFName.of(key)));
|
|
5797
5999
|
if (alpha instanceof PDFNumber && alpha.asNumber() < 1)
|
|
5798
6000
|
return true;
|
|
5799
6001
|
}
|
|
6002
|
+
const bm = ctx.lookup(dict.get(PDFName.of("BM")));
|
|
6003
|
+
const mode = bm instanceof PDFArray ? bm.get(0) : bm;
|
|
6004
|
+
if (mode && !["/Normal", "/Compatible"].includes(String(mode)))
|
|
6005
|
+
return true;
|
|
5800
6006
|
}
|
|
5801
|
-
const group = dict.get(PDFName.of("Group"));
|
|
5802
|
-
|
|
5803
|
-
|
|
5804
|
-
|
|
6007
|
+
const group = ctx.lookup(dict.get(PDFName.of("Group")));
|
|
6008
|
+
return group instanceof PDFDict && String(group.get(PDFName.of("S"))) === "/Transparency";
|
|
6009
|
+
};
|
|
6010
|
+
const reaches = (root) => {
|
|
6011
|
+
const seen = new Set;
|
|
6012
|
+
const stack = [root];
|
|
6013
|
+
while (stack.length) {
|
|
6014
|
+
const node = stack.pop();
|
|
6015
|
+
const obj = node instanceof PDFRef ? ctx.lookup(node) : node;
|
|
6016
|
+
if (!obj || seen.has(obj))
|
|
6017
|
+
continue;
|
|
6018
|
+
seen.add(obj);
|
|
6019
|
+
if (obj instanceof PDFArray) {
|
|
6020
|
+
stack.push(...obj.asArray());
|
|
6021
|
+
continue;
|
|
6022
|
+
}
|
|
6023
|
+
const dict = obj instanceof PDFRawStream ? obj.dict : obj instanceof PDFDict ? obj : undefined;
|
|
6024
|
+
if (!dict)
|
|
6025
|
+
continue;
|
|
6026
|
+
if (dictHasTransparency(dict))
|
|
5805
6027
|
return true;
|
|
6028
|
+
for (const [key, value] of dict.entries()) {
|
|
6029
|
+
if (!SKIP.has(key.asString().slice(1)))
|
|
6030
|
+
stack.push(value);
|
|
6031
|
+
}
|
|
5806
6032
|
}
|
|
5807
|
-
|
|
5808
|
-
|
|
6033
|
+
return false;
|
|
6034
|
+
};
|
|
6035
|
+
const pages = [];
|
|
6036
|
+
doc.getPages().forEach((page, i) => {
|
|
6037
|
+
if (reaches(page.node))
|
|
6038
|
+
pages.push(i + 1);
|
|
6039
|
+
});
|
|
6040
|
+
return pages;
|
|
5809
6041
|
}
|
|
5810
6042
|
async function findPostScriptShadingPages(pdfBytes) {
|
|
5811
6043
|
const { PDFDocument, PDFDict, PDFName, PDFNumber, PDFRawStream, PDFRef } = await import("pdf-lib");
|
|
@@ -5876,6 +6108,75 @@ async function stripAnnotations(pdfPath, stagingDir) {
|
|
|
5876
6108
|
const out = await doc.save();
|
|
5877
6109
|
await writeFile3(pdfPath, out);
|
|
5878
6110
|
}
|
|
6111
|
+
function planTransparentPages(transparent, reasons, flattenPages, gradientPages) {
|
|
6112
|
+
const split = [];
|
|
6113
|
+
const artOnly = [];
|
|
6114
|
+
const kept = new Map;
|
|
6115
|
+
for (const n of transparent) {
|
|
6116
|
+
const reason = reasons.get(n);
|
|
6117
|
+
if (reason === "no-text")
|
|
6118
|
+
artOnly.push(n);
|
|
6119
|
+
else if (flattenPages.includes(n))
|
|
6120
|
+
kept.set(n, "listed");
|
|
6121
|
+
else if (reason)
|
|
6122
|
+
kept.set(n, reason);
|
|
6123
|
+
else if (gradientPages.includes(n))
|
|
6124
|
+
kept.set(n, "gradient");
|
|
6125
|
+
else
|
|
6126
|
+
split.push(n);
|
|
6127
|
+
}
|
|
6128
|
+
return { split, artOnly, kept };
|
|
6129
|
+
}
|
|
6130
|
+
async function flattenTransparentPages(pdfPath, pageNumbers, stagingDir, dpi = 300) {
|
|
6131
|
+
const pages = [...new Set(pageNumbers)].sort((a, b) => a - b);
|
|
6132
|
+
if (pages.length === 0)
|
|
6133
|
+
return;
|
|
6134
|
+
const ghostscript = await resolveGhostscript();
|
|
6135
|
+
if (!ghostscript) {
|
|
6136
|
+
throw new Error("Ghostscript executable not found. Install Ghostscript or set GHOSTSCRIPT_PATH to its command-line executable.");
|
|
6137
|
+
}
|
|
6138
|
+
const art = join3(stagingDir, "flatten-art.pdf");
|
|
6139
|
+
const text = join3(stagingDir, "flatten-text.pdf");
|
|
6140
|
+
const pageList = `-sPageList=${pages.join(",")}`;
|
|
6141
|
+
const gs = (...args) => run(ghostscript, [
|
|
6142
|
+
"-q",
|
|
6143
|
+
"-dBATCH",
|
|
6144
|
+
"-dNOPAUSE",
|
|
6145
|
+
"-dSAFER",
|
|
6146
|
+
"-dPreserveAnnots=false",
|
|
6147
|
+
"-dNO_PDFMARK_OUTLINES",
|
|
6148
|
+
...args
|
|
6149
|
+
]);
|
|
6150
|
+
try {
|
|
6151
|
+
await gs(pageList, "-sDEVICE=pdfimage24", "-dFILTERTEXT", `-r${dpi}`, `-sOutputFile=${art}`, pdfPath);
|
|
6152
|
+
await gs(pageList, "-sDEVICE=pdfwrite", "-dNOTRANSPARENCY", "-dFILTERIMAGE", "-dFILTERVECTOR", "-dCompatibilityLevel=1.3", `-sOutputFile=${text}`, pdfPath);
|
|
6153
|
+
const { PDFDocument, PDFName } = await import("pdf-lib");
|
|
6154
|
+
const doc = await PDFDocument.load(await readFile9(pdfPath), { updateMetadata: false });
|
|
6155
|
+
const artDoc = await PDFDocument.load(await readFile9(art));
|
|
6156
|
+
const textDoc = await PDFDocument.load(await readFile9(text));
|
|
6157
|
+
if (artDoc.getPageCount() !== pages.length || textDoc.getPageCount() !== pages.length) {
|
|
6158
|
+
throw new Error(`Ghostscript returned ${artDoc.getPageCount()} artwork and ${textDoc.getPageCount()} text pages for ${pages.length} transparent pages.`);
|
|
6159
|
+
}
|
|
6160
|
+
const artPages = await doc.embedPages(artDoc.getPages());
|
|
6161
|
+
const withText = textDoc.getPages().filter((p) => p.node.Contents());
|
|
6162
|
+
const embeddedText = await doc.embedPages(withText);
|
|
6163
|
+
const textPages = textDoc.getPages().map((p) => embeddedText[withText.indexOf(p)]);
|
|
6164
|
+
pages.forEach((pageNumber, i) => {
|
|
6165
|
+
const page = doc.getPage(pageNumber - 1);
|
|
6166
|
+
const { x, y, width, height } = page.getMediaBox();
|
|
6167
|
+
page.node.set(PDFName.of("Contents"), doc.context.obj([]));
|
|
6168
|
+
page.node.set(PDFName.of("Resources"), doc.context.obj({}));
|
|
6169
|
+
page.node.delete(PDFName.of("Group"));
|
|
6170
|
+
page.drawPage(artPages[i], { x, y, width, height });
|
|
6171
|
+
const textPage = textPages[i];
|
|
6172
|
+
if (textPage)
|
|
6173
|
+
page.drawPage(textPage, { x, y, width, height });
|
|
6174
|
+
});
|
|
6175
|
+
await writeFile3(pdfPath, await doc.save());
|
|
6176
|
+
} finally {
|
|
6177
|
+
await Promise.all([art, text].map((f) => unlink2(f).catch(() => {})));
|
|
6178
|
+
}
|
|
6179
|
+
}
|
|
5879
6180
|
function makePdfxDefPs(params) {
|
|
5880
6181
|
const pdfxVersion = params.pdfx === "x3" ? "PDF/X-3:2002" : "PDF/X-1:2001";
|
|
5881
6182
|
const pdfxConformance = params.pdfx === "x1a" ? "PDF/X-1a:2001" : null;
|
|
@@ -5967,6 +6268,10 @@ async function convertToPdfxCmyk(inputPdf, outPdf, config) {
|
|
|
5967
6268
|
"-dDownsampleColorImages=false",
|
|
5968
6269
|
"-dDownsampleGrayImages=false",
|
|
5969
6270
|
"-dDownsampleMonoImages=false",
|
|
6271
|
+
"-dAutoFilterColorImages=false",
|
|
6272
|
+
"-dColorImageFilter=/FlateEncode",
|
|
6273
|
+
"-dAutoFilterGrayImages=false",
|
|
6274
|
+
"-dGrayImageFilter=/FlateEncode",
|
|
5970
6275
|
...config.rasterDpi ? [`-r${config.rasterDpi}`] : [],
|
|
5971
6276
|
"-sProcessColorModel=DeviceCMYK",
|
|
5972
6277
|
"-sColorConversionStrategy=CMYK",
|
|
@@ -6014,117 +6319,6 @@ import { mkdir as mkdir5, readFile as readFile10, writeFile as writeFile4 } from
|
|
|
6014
6319
|
import { createHash as createHash3 } from "node:crypto";
|
|
6015
6320
|
import path10 from "node:path";
|
|
6016
6321
|
import git from "isomorphic-git";
|
|
6017
|
-
// package.json
|
|
6018
|
-
var package_default = {
|
|
6019
|
-
name: "gutterpress",
|
|
6020
|
-
version: "0.11.20-alpha.2",
|
|
6021
|
-
description: "Markdown-to-PDF converter for professional print layout using a native Chromium print engine and Ghostscript.",
|
|
6022
|
-
author: "itlackey",
|
|
6023
|
-
license: "MPL-2.0",
|
|
6024
|
-
keywords: [
|
|
6025
|
-
"markdown",
|
|
6026
|
-
"pdf",
|
|
6027
|
-
"print",
|
|
6028
|
-
"ghostscript",
|
|
6029
|
-
"book",
|
|
6030
|
-
"publishing",
|
|
6031
|
-
"zine"
|
|
6032
|
-
],
|
|
6033
|
-
repository: {
|
|
6034
|
-
type: "git",
|
|
6035
|
-
url: "https://github.com/dimm-city/gutterpress.git"
|
|
6036
|
-
},
|
|
6037
|
-
homepage: "https://github.com/dimm-city/gutterpress#readme",
|
|
6038
|
-
bugs: {
|
|
6039
|
-
url: "https://github.com/dimm-city/gutterpress/issues"
|
|
6040
|
-
},
|
|
6041
|
-
type: "module",
|
|
6042
|
-
main: "./dist/index.js",
|
|
6043
|
-
types: "./dist/index.d.ts",
|
|
6044
|
-
bin: {
|
|
6045
|
-
gutterpress: "./dist/cli.js"
|
|
6046
|
-
},
|
|
6047
|
-
exports: {
|
|
6048
|
-
".": {
|
|
6049
|
-
types: "./dist/index.d.ts",
|
|
6050
|
-
default: "./dist/index.js"
|
|
6051
|
-
},
|
|
6052
|
-
"./api": {
|
|
6053
|
-
types: "./dist/api/index.d.ts",
|
|
6054
|
-
default: "./dist/api/index.js"
|
|
6055
|
-
},
|
|
6056
|
-
"./render": {
|
|
6057
|
-
types: "./dist/render.d.ts",
|
|
6058
|
-
default: "./dist/render.js"
|
|
6059
|
-
}
|
|
6060
|
-
},
|
|
6061
|
-
files: [
|
|
6062
|
-
"dist/",
|
|
6063
|
-
"README.md",
|
|
6064
|
-
"LICENSE"
|
|
6065
|
-
],
|
|
6066
|
-
scripts: {
|
|
6067
|
-
"build:library": "bun scripts/build-engine-bundles.mjs && rimraf dist && bun build src/index.ts src/api/index.ts --target=node --packages=external --splitting --outdir=dist && bun build src/render.ts --target=node --packages=external --outdir=dist && node scripts/check-render-pure.mjs && tsc -p tsconfig.build.json",
|
|
6068
|
-
build: "bun run build:library && bun build src/cli.ts --target=node --packages=external --splitting --outdir=dist",
|
|
6069
|
-
prepublishOnly: "bun run build",
|
|
6070
|
-
test: "bun test",
|
|
6071
|
-
typecheck: "tsc --noEmit",
|
|
6072
|
-
"typecheck:engine-browser": "tsc --noEmit -p src/engine/browser.tsconfig.json",
|
|
6073
|
-
"parity:gate": "bun scripts/native-parity-gate.ts"
|
|
6074
|
-
},
|
|
6075
|
-
engines: {
|
|
6076
|
-
bun: ">=1.0.0",
|
|
6077
|
-
node: ">=22.0.0"
|
|
6078
|
-
},
|
|
6079
|
-
dependencies: {
|
|
6080
|
-
chokidar: "^5.0.0",
|
|
6081
|
-
citty: "^0.2.0",
|
|
6082
|
-
diff3: "0.0.3",
|
|
6083
|
-
fflate: "0.8.3",
|
|
6084
|
-
glob: "^13.0.0",
|
|
6085
|
-
htmlhint: "^1.9.2",
|
|
6086
|
-
ignore: "^5.3.2",
|
|
6087
|
-
"isomorphic-git": "^1.38.4",
|
|
6088
|
-
"markdown-it": "^14.3.2",
|
|
6089
|
-
"markdown-it-abbr": "^2.0.0",
|
|
6090
|
-
"markdown-it-attrs": "^4.3.0",
|
|
6091
|
-
"markdown-it-deflist": "^3.0.1",
|
|
6092
|
-
"markdown-it-footnote": "^4.0.0",
|
|
6093
|
-
"markdown-it-mark": "^4.0.0",
|
|
6094
|
-
"markdown-it-source-map": "^0.1.1",
|
|
6095
|
-
"markdown-it-sub": "^2.0.0",
|
|
6096
|
-
"markdown-it-sup": "^2.0.0",
|
|
6097
|
-
markdownlint: "^0.40.0",
|
|
6098
|
-
"pdf-lib": "^1.17.1",
|
|
6099
|
-
postcss: "^8.5.18",
|
|
6100
|
-
"resolve.exports": "2.0.3",
|
|
6101
|
-
semver: "7.8.0",
|
|
6102
|
-
tar: "7.5.22",
|
|
6103
|
-
unpdf: "^1.6.2",
|
|
6104
|
-
ws: "^8.21.0",
|
|
6105
|
-
yaml: "^2.8.2"
|
|
6106
|
-
},
|
|
6107
|
-
devDependencies: {
|
|
6108
|
-
"@types/bun": "1.3.14",
|
|
6109
|
-
"@types/markdown-it": "^14.1.2",
|
|
6110
|
-
"@types/node": "^22.0.0",
|
|
6111
|
-
"@types/semver": "^7.7.1",
|
|
6112
|
-
"@types/ws": "^8.5.13",
|
|
6113
|
-
playwright: "^1.60.0",
|
|
6114
|
-
rimraf: "^6.0.0",
|
|
6115
|
-
typescript: "^5"
|
|
6116
|
-
}
|
|
6117
|
-
};
|
|
6118
|
-
|
|
6119
|
-
// src/lib/version.ts
|
|
6120
|
-
var PACKAGE_META = {
|
|
6121
|
-
version: package_default.version ?? "unknown",
|
|
6122
|
-
dependencies: package_default.dependencies ?? {},
|
|
6123
|
-
devDependencies: package_default.devDependencies ?? {}
|
|
6124
|
-
};
|
|
6125
|
-
var PACKAGE_VERSION = PACKAGE_META.version;
|
|
6126
|
-
|
|
6127
|
-
// src/lib/build-fingerprint.ts
|
|
6128
6322
|
var FINGERPRINT_FILENAME = "build-fingerprint.json";
|
|
6129
6323
|
var VERSION_TIMEOUT_MS = 4000;
|
|
6130
6324
|
function toJsonValue(value) {
|
|
@@ -6272,7 +6466,10 @@ async function writeBuildFingerprint(input) {
|
|
|
6272
6466
|
resolvedFlavor: input.pdfx.resolvedFlavor,
|
|
6273
6467
|
iccPath: input.pdfx.iccPath,
|
|
6274
6468
|
stripAnnotations: input.pdfx.stripAnnotations,
|
|
6275
|
-
blackText: input.pdfx.blackText ?? null
|
|
6469
|
+
blackText: input.pdfx.blackText ?? null,
|
|
6470
|
+
transparency: input.pdfx.transparency ?? null,
|
|
6471
|
+
flattenPages: input.pdfx.flattenPages ?? null,
|
|
6472
|
+
rasterDpi: input.pdfx.rasterDpi ?? null
|
|
6276
6473
|
},
|
|
6277
6474
|
outputDir: input.recordedOutputDir ? path10.resolve(input.recordedOutputDir) : outputDir
|
|
6278
6475
|
},
|
|
@@ -6614,346 +6811,6 @@ function inspectionFailed(checkId, message, extra = {}) {
|
|
|
6614
6811
|
};
|
|
6615
6812
|
}
|
|
6616
6813
|
|
|
6617
|
-
// src/lib/pdf-inspect.ts
|
|
6618
|
-
import { stat as stat2, readFile as readFile13 } from "node:fs/promises";
|
|
6619
|
-
import { getDocumentProxy } from "unpdf";
|
|
6620
|
-
import * as pdfjs from "unpdf/pdfjs";
|
|
6621
|
-
function getOps(mod) {
|
|
6622
|
-
if ("OPS" in mod && mod.OPS && typeof mod.OPS === "object") {
|
|
6623
|
-
return mod.OPS;
|
|
6624
|
-
}
|
|
6625
|
-
throw new Error("unpdf/pdfjs missing OPS export");
|
|
6626
|
-
}
|
|
6627
|
-
var OPS = getOps(pdfjs);
|
|
6628
|
-
var docCache = new Map;
|
|
6629
|
-
var DOC_CACHE_MAX = 8;
|
|
6630
|
-
function destroyEntry(entry) {
|
|
6631
|
-
entry.doc.then((d) => d.destroy()).catch(() => {});
|
|
6632
|
-
}
|
|
6633
|
-
var EVICT_DESTROY_GRACE_MS = 60000;
|
|
6634
|
-
var gracePending = new Map;
|
|
6635
|
-
function destroyEntryAfterGrace(entry) {
|
|
6636
|
-
const t = setTimeout(() => {
|
|
6637
|
-
gracePending.delete(t);
|
|
6638
|
-
destroyEntry(entry);
|
|
6639
|
-
}, EVICT_DESTROY_GRACE_MS);
|
|
6640
|
-
t.unref?.();
|
|
6641
|
-
gracePending.set(t, entry);
|
|
6642
|
-
}
|
|
6643
|
-
function evictLru() {
|
|
6644
|
-
while (docCache.size > DOC_CACHE_MAX) {
|
|
6645
|
-
const oldestKey = docCache.keys().next().value;
|
|
6646
|
-
if (oldestKey === undefined)
|
|
6647
|
-
break;
|
|
6648
|
-
const evicted = docCache.get(oldestKey);
|
|
6649
|
-
docCache.delete(oldestKey);
|
|
6650
|
-
if (evicted)
|
|
6651
|
-
destroyEntryAfterGrace(evicted);
|
|
6652
|
-
}
|
|
6653
|
-
}
|
|
6654
|
-
async function loadPdf(path11) {
|
|
6655
|
-
let st;
|
|
6656
|
-
try {
|
|
6657
|
-
st = await stat2(path11);
|
|
6658
|
-
} catch {
|
|
6659
|
-
return null;
|
|
6660
|
-
}
|
|
6661
|
-
const hit = docCache.get(path11);
|
|
6662
|
-
if (hit && hit.mtimeMs === st.mtimeMs && hit.size === st.size) {
|
|
6663
|
-
docCache.delete(path11);
|
|
6664
|
-
docCache.set(path11, hit);
|
|
6665
|
-
try {
|
|
6666
|
-
return await hit.doc;
|
|
6667
|
-
} catch {
|
|
6668
|
-
return null;
|
|
6669
|
-
}
|
|
6670
|
-
}
|
|
6671
|
-
if (hit)
|
|
6672
|
-
destroyEntry(hit);
|
|
6673
|
-
const docPromise = readFile13(path11).then((buf) => getDocumentProxy(new Uint8Array(buf)));
|
|
6674
|
-
docCache.delete(path11);
|
|
6675
|
-
docCache.set(path11, { mtimeMs: st.mtimeMs, size: st.size, doc: docPromise });
|
|
6676
|
-
evictLru();
|
|
6677
|
-
try {
|
|
6678
|
-
return await docPromise;
|
|
6679
|
-
} catch {
|
|
6680
|
-
if (docCache.get(path11)?.doc === docPromise)
|
|
6681
|
-
docCache.delete(path11);
|
|
6682
|
-
return null;
|
|
6683
|
-
}
|
|
6684
|
-
}
|
|
6685
|
-
var activeRetains = 0;
|
|
6686
|
-
function retainPdfCache() {
|
|
6687
|
-
activeRetains++;
|
|
6688
|
-
let released = false;
|
|
6689
|
-
return () => {
|
|
6690
|
-
if (released)
|
|
6691
|
-
return;
|
|
6692
|
-
released = true;
|
|
6693
|
-
activeRetains--;
|
|
6694
|
-
if (activeRetains === 0)
|
|
6695
|
-
clearPdfCache();
|
|
6696
|
-
};
|
|
6697
|
-
}
|
|
6698
|
-
function clearPdfCache() {
|
|
6699
|
-
for (const [t, entry] of gracePending) {
|
|
6700
|
-
clearTimeout(t);
|
|
6701
|
-
destroyEntry(entry);
|
|
6702
|
-
}
|
|
6703
|
-
gracePending.clear();
|
|
6704
|
-
for (const entry of docCache.values())
|
|
6705
|
-
destroyEntry(entry);
|
|
6706
|
-
docCache.clear();
|
|
6707
|
-
}
|
|
6708
|
-
function getPageSize(page) {
|
|
6709
|
-
const vp = page.getViewport({ scale: 1 });
|
|
6710
|
-
return { w: vp.width, h: vp.height };
|
|
6711
|
-
}
|
|
6712
|
-
async function getOutlineCount(doc) {
|
|
6713
|
-
try {
|
|
6714
|
-
const outline = await doc.getOutline();
|
|
6715
|
-
return outline ? outline.length : 0;
|
|
6716
|
-
} catch {
|
|
6717
|
-
return 0;
|
|
6718
|
-
}
|
|
6719
|
-
}
|
|
6720
|
-
async function getPageLabels(doc) {
|
|
6721
|
-
try {
|
|
6722
|
-
return await doc.getPageLabels();
|
|
6723
|
-
} catch {
|
|
6724
|
-
return null;
|
|
6725
|
-
}
|
|
6726
|
-
}
|
|
6727
|
-
async function countLinkAnnotations(doc, stopAtFirst = false) {
|
|
6728
|
-
let count = 0;
|
|
6729
|
-
for (let i = 1;i <= doc.numPages; i++) {
|
|
6730
|
-
try {
|
|
6731
|
-
const page = await doc.getPage(i);
|
|
6732
|
-
const annots = await page.getAnnotations();
|
|
6733
|
-
for (const a of annots) {
|
|
6734
|
-
if (a.subtype === "Link") {
|
|
6735
|
-
count++;
|
|
6736
|
-
if (stopAtFirst)
|
|
6737
|
-
return count;
|
|
6738
|
-
}
|
|
6739
|
-
}
|
|
6740
|
-
} catch {}
|
|
6741
|
-
}
|
|
6742
|
-
return count;
|
|
6743
|
-
}
|
|
6744
|
-
var textCache = new WeakMap;
|
|
6745
|
-
function getTextPass(doc) {
|
|
6746
|
-
let p = textCache.get(doc);
|
|
6747
|
-
if (!p) {
|
|
6748
|
-
p = (async () => {
|
|
6749
|
-
const textByPage = [];
|
|
6750
|
-
const positions = [];
|
|
6751
|
-
const runsByPage = [];
|
|
6752
|
-
for (let i = 1;i <= doc.numPages; i++) {
|
|
6753
|
-
try {
|
|
6754
|
-
const page = await doc.getPage(i);
|
|
6755
|
-
const tc = await page.getTextContent();
|
|
6756
|
-
let pageText = "";
|
|
6757
|
-
const runs = [];
|
|
6758
|
-
for (const item of tc.items) {
|
|
6759
|
-
const it = item;
|
|
6760
|
-
if (typeof it.str !== "string")
|
|
6761
|
-
continue;
|
|
6762
|
-
pageText += it.str;
|
|
6763
|
-
if (it.transform && it.str.trim().length > 0) {
|
|
6764
|
-
const x = it.transform[4];
|
|
6765
|
-
const y = it.transform[5];
|
|
6766
|
-
positions.push({ x, y });
|
|
6767
|
-
runs.push({ s: it.str, x, y, w: it.width ?? 0, h: it.height ?? 0 });
|
|
6768
|
-
}
|
|
6769
|
-
}
|
|
6770
|
-
textByPage.push(pageText);
|
|
6771
|
-
runsByPage.push(runs);
|
|
6772
|
-
} catch {
|
|
6773
|
-
textByPage.push("");
|
|
6774
|
-
runsByPage.push([]);
|
|
6775
|
-
}
|
|
6776
|
-
}
|
|
6777
|
-
return { textByPage, positions, runsByPage };
|
|
6778
|
-
})();
|
|
6779
|
-
textCache.set(doc, p);
|
|
6780
|
-
}
|
|
6781
|
-
return p;
|
|
6782
|
-
}
|
|
6783
|
-
var opCache = new WeakMap;
|
|
6784
|
-
function multiply(m1, m2) {
|
|
6785
|
-
return [
|
|
6786
|
-
m1[0] * m2[0] + m1[2] * m2[1],
|
|
6787
|
-
m1[1] * m2[0] + m1[3] * m2[1],
|
|
6788
|
-
m1[0] * m2[2] + m1[2] * m2[3],
|
|
6789
|
-
m1[1] * m2[2] + m1[3] * m2[3],
|
|
6790
|
-
m1[0] * m2[4] + m1[2] * m2[5] + m1[4],
|
|
6791
|
-
m1[1] * m2[4] + m1[3] * m2[5] + m1[5]
|
|
6792
|
-
];
|
|
6793
|
-
}
|
|
6794
|
-
function fontIsEmbedded(f) {
|
|
6795
|
-
if (f.isType3Font)
|
|
6796
|
-
return true;
|
|
6797
|
-
if (f.missingFile === true)
|
|
6798
|
-
return false;
|
|
6799
|
-
if (f.isStandardFont === true)
|
|
6800
|
-
return false;
|
|
6801
|
-
return true;
|
|
6802
|
-
}
|
|
6803
|
-
function getOpPass(doc) {
|
|
6804
|
-
let p = opCache.get(doc);
|
|
6805
|
-
if (!p) {
|
|
6806
|
-
p = (async () => {
|
|
6807
|
-
const imagesByPage = new Map;
|
|
6808
|
-
const fonts = [];
|
|
6809
|
-
const seenFonts = new Set;
|
|
6810
|
-
for (let i = 1;i <= doc.numPages; i++) {
|
|
6811
|
-
let page;
|
|
6812
|
-
try {
|
|
6813
|
-
page = await doc.getPage(i);
|
|
6814
|
-
} catch {
|
|
6815
|
-
continue;
|
|
6816
|
-
}
|
|
6817
|
-
let ops;
|
|
6818
|
-
try {
|
|
6819
|
-
ops = await page.getOperatorList();
|
|
6820
|
-
} catch {
|
|
6821
|
-
continue;
|
|
6822
|
-
}
|
|
6823
|
-
let ctm = [1, 0, 0, 1, 0, 0];
|
|
6824
|
-
const stack = [];
|
|
6825
|
-
const pageImages = [];
|
|
6826
|
-
for (let j = 0;j < ops.fnArray.length; j++) {
|
|
6827
|
-
const fn = ops.fnArray[j];
|
|
6828
|
-
const args = ops.argsArray[j];
|
|
6829
|
-
if (fn === OPS.save) {
|
|
6830
|
-
stack.push(ctm.slice());
|
|
6831
|
-
} else if (fn === OPS.restore) {
|
|
6832
|
-
ctm = stack.pop() ?? ctm;
|
|
6833
|
-
} else if (fn === OPS.transform) {
|
|
6834
|
-
ctm = multiply(ctm, args);
|
|
6835
|
-
} else if (fn === OPS.paintImageXObject || fn === OPS.paintImageXObjectRepeat || fn === OPS.paintInlineImageXObject) {
|
|
6836
|
-
const name = typeof args[0] === "string" ? args[0] : "(inline)";
|
|
6837
|
-
pageImages.push({
|
|
6838
|
-
name,
|
|
6839
|
-
placedW: Math.hypot(ctm[0], ctm[1]),
|
|
6840
|
-
placedH: Math.hypot(ctm[2], ctm[3]),
|
|
6841
|
-
x: ctm[4],
|
|
6842
|
-
y: ctm[5],
|
|
6843
|
-
page: i
|
|
6844
|
-
});
|
|
6845
|
-
} else if (fn === OPS.setFont) {
|
|
6846
|
-
const ref = args[0];
|
|
6847
|
-
if (typeof ref === "string" && !seenFonts.has(ref)) {
|
|
6848
|
-
seenFonts.add(ref);
|
|
6849
|
-
try {
|
|
6850
|
-
if (page.commonObjs.has(ref)) {
|
|
6851
|
-
const f = page.commonObjs.get(ref);
|
|
6852
|
-
fonts.push({
|
|
6853
|
-
name: f?.name ?? ref,
|
|
6854
|
-
embedded: fontIsEmbedded(f ?? {})
|
|
6855
|
-
});
|
|
6856
|
-
}
|
|
6857
|
-
} catch {}
|
|
6858
|
-
}
|
|
6859
|
-
}
|
|
6860
|
-
}
|
|
6861
|
-
if (pageImages.length > 0)
|
|
6862
|
-
imagesByPage.set(i, pageImages);
|
|
6863
|
-
}
|
|
6864
|
-
return { imagesByPage, fonts };
|
|
6865
|
-
})();
|
|
6866
|
-
opCache.set(doc, p);
|
|
6867
|
-
}
|
|
6868
|
-
return p;
|
|
6869
|
-
}
|
|
6870
|
-
function getImagePixelSize(page, name, timeoutMs = 2000) {
|
|
6871
|
-
return new Promise((resolve6) => {
|
|
6872
|
-
let done = false;
|
|
6873
|
-
const finish = (v) => {
|
|
6874
|
-
if (!done) {
|
|
6875
|
-
done = true;
|
|
6876
|
-
resolve6(v);
|
|
6877
|
-
}
|
|
6878
|
-
};
|
|
6879
|
-
const t = setTimeout(() => finish(null), timeoutMs);
|
|
6880
|
-
try {
|
|
6881
|
-
page.objs.get(name, (obj) => {
|
|
6882
|
-
clearTimeout(t);
|
|
6883
|
-
finish(obj && obj.width && obj.height ? { width: obj.width, height: obj.height } : null);
|
|
6884
|
-
});
|
|
6885
|
-
} catch {
|
|
6886
|
-
clearTimeout(t);
|
|
6887
|
-
finish(null);
|
|
6888
|
-
}
|
|
6889
|
-
});
|
|
6890
|
-
}
|
|
6891
|
-
var PAINT_OPS = new Set([
|
|
6892
|
-
"stroke",
|
|
6893
|
-
"closeStroke",
|
|
6894
|
-
"fill",
|
|
6895
|
-
"eoFill",
|
|
6896
|
-
"fillStroke",
|
|
6897
|
-
"eoFillStroke",
|
|
6898
|
-
"closeFillStroke",
|
|
6899
|
-
"closeEOFillStroke",
|
|
6900
|
-
"shadingFill",
|
|
6901
|
-
"paintImageXObject",
|
|
6902
|
-
"paintInlineImageXObject",
|
|
6903
|
-
"paintImageXObjectRepeat",
|
|
6904
|
-
"paintImageMaskXObject",
|
|
6905
|
-
"paintImageMaskXObjectGroup",
|
|
6906
|
-
"paintImageMaskXObjectRepeat",
|
|
6907
|
-
"paintSolidColorImageMask",
|
|
6908
|
-
"showText",
|
|
6909
|
-
"showSpacedText",
|
|
6910
|
-
"nextLineShowText",
|
|
6911
|
-
"nextLineSetSpacingShowText"
|
|
6912
|
-
].map((name) => OPS[name]).filter((op) => op !== undefined));
|
|
6913
|
-
async function pageHasMarks(doc, pageNum) {
|
|
6914
|
-
const ops = await (await doc.getPage(pageNum)).getOperatorList();
|
|
6915
|
-
return ops.fnArray.some((fn, i) => fn === OPS.constructPath ? PAINT_OPS.has(ops.argsArray[i][0]) : PAINT_OPS.has(fn));
|
|
6916
|
-
}
|
|
6917
|
-
async function getImageResolutions(doc) {
|
|
6918
|
-
const { imagesByPage } = await getOpPass(doc);
|
|
6919
|
-
const out = [];
|
|
6920
|
-
for (const [pageNum, imgs] of imagesByPage) {
|
|
6921
|
-
let page;
|
|
6922
|
-
try {
|
|
6923
|
-
page = await doc.getPage(pageNum);
|
|
6924
|
-
} catch {
|
|
6925
|
-
continue;
|
|
6926
|
-
}
|
|
6927
|
-
for (const img of imgs) {
|
|
6928
|
-
if (img.name === "(inline)")
|
|
6929
|
-
continue;
|
|
6930
|
-
const px = await getImagePixelSize(page, img.name);
|
|
6931
|
-
if (!px)
|
|
6932
|
-
continue;
|
|
6933
|
-
const placedWin = img.placedW / 72;
|
|
6934
|
-
const placedHin = img.placedH / 72;
|
|
6935
|
-
if (placedWin <= 0 || placedHin <= 0)
|
|
6936
|
-
continue;
|
|
6937
|
-
out.push({
|
|
6938
|
-
page: pageNum,
|
|
6939
|
-
xDpi: px.width / placedWin,
|
|
6940
|
-
yDpi: px.height / placedHin
|
|
6941
|
-
});
|
|
6942
|
-
}
|
|
6943
|
-
}
|
|
6944
|
-
return out;
|
|
6945
|
-
}
|
|
6946
|
-
async function isLoadable(doc) {
|
|
6947
|
-
try {
|
|
6948
|
-
for (let i = 1;i <= doc.numPages; i++) {
|
|
6949
|
-
await doc.getPage(i);
|
|
6950
|
-
}
|
|
6951
|
-
return true;
|
|
6952
|
-
} catch {
|
|
6953
|
-
return false;
|
|
6954
|
-
}
|
|
6955
|
-
}
|
|
6956
|
-
|
|
6957
6814
|
// src/checks/pdf/qpdf-structure.ts
|
|
6958
6815
|
var check2 = {
|
|
6959
6816
|
id: "pdf.structure.qpdf",
|
|
@@ -7228,9 +7085,9 @@ var check5 = {
|
|
|
7228
7085
|
registerCheck(check5);
|
|
7229
7086
|
|
|
7230
7087
|
// src/lib/pdf-parse.ts
|
|
7231
|
-
import { readFile as
|
|
7088
|
+
import { readFile as readFile13 } from "node:fs/promises";
|
|
7232
7089
|
async function readPdfBytes(pdfPath) {
|
|
7233
|
-
return
|
|
7090
|
+
return readFile13(pdfPath, "latin1");
|
|
7234
7091
|
}
|
|
7235
7092
|
function parseInkCov(out) {
|
|
7236
7093
|
const lines = out.split(/\r?\n/).filter((l) => l.includes("CMYK"));
|
|
@@ -7491,7 +7348,7 @@ var check9 = {
|
|
|
7491
7348
|
registerCheck(check9);
|
|
7492
7349
|
|
|
7493
7350
|
// src/checks/pdf/black-text.ts
|
|
7494
|
-
import { readFile as
|
|
7351
|
+
import { readFile as readFile14 } from "node:fs/promises";
|
|
7495
7352
|
var check10 = {
|
|
7496
7353
|
id: "pdf.print.black-text",
|
|
7497
7354
|
name: "Black Text",
|
|
@@ -7504,7 +7361,7 @@ var check10 = {
|
|
|
7504
7361
|
return [];
|
|
7505
7362
|
try {
|
|
7506
7363
|
const { findRichBlackText, LARGE_TEXT_PT } = await import("./black-text-gray-7dz61456.js");
|
|
7507
|
-
const found = await findRichBlackText(await
|
|
7364
|
+
const found = await findRichBlackText(await readFile14(ctx.pdfPath));
|
|
7508
7365
|
if (found.runs === 0)
|
|
7509
7366
|
return [];
|
|
7510
7367
|
return [
|
|
@@ -7894,7 +7751,7 @@ registerCheck(check19);
|
|
|
7894
7751
|
|
|
7895
7752
|
// src/checks/source/htmlhint.ts
|
|
7896
7753
|
import { existsSync as existsSync9 } from "node:fs";
|
|
7897
|
-
import { readFile as
|
|
7754
|
+
import { readFile as readFile15 } from "node:fs/promises";
|
|
7898
7755
|
import htmlhint from "htmlhint";
|
|
7899
7756
|
var { HTMLHint } = htmlhint;
|
|
7900
7757
|
var CONFIG_NAMES2 = [".htmlhintrc"];
|
|
@@ -7914,8 +7771,8 @@ var check20 = {
|
|
|
7914
7771
|
const resolvedConfig = findConfigFile(ctx.inputDir, CONFIG_NAMES2, configPath);
|
|
7915
7772
|
if (!resolvedConfig && !configPath)
|
|
7916
7773
|
return [];
|
|
7917
|
-
const ruleset = resolvedConfig ? JSON.parse(await
|
|
7918
|
-
const html = await
|
|
7774
|
+
const ruleset = resolvedConfig ? JSON.parse(await readFile15(resolvedConfig, "utf8")) : HTMLHint.defaultRuleset;
|
|
7775
|
+
const html = await readFile15(ctx.htmlPath, "utf8");
|
|
7919
7776
|
const messages = HTMLHint.verify(html, ruleset);
|
|
7920
7777
|
return messages.map((m) => ({
|
|
7921
7778
|
checkId: check20.id,
|
|
@@ -7930,7 +7787,7 @@ var check20 = {
|
|
|
7930
7787
|
registerCheck(check20);
|
|
7931
7788
|
|
|
7932
7789
|
// src/checks/source/stylelint.ts
|
|
7933
|
-
import { readFile as
|
|
7790
|
+
import { readFile as readFile16 } from "node:fs/promises";
|
|
7934
7791
|
|
|
7935
7792
|
// src/lib/printsafe.ts
|
|
7936
7793
|
import postcss2 from "postcss";
|
|
@@ -8272,7 +8129,7 @@ function checkCssRaw(css, from) {
|
|
|
8272
8129
|
warnings.push({
|
|
8273
8130
|
rule: ruleRiskyProps,
|
|
8274
8131
|
severity: "warning",
|
|
8275
|
-
message: `"${decl.prop}: ${decl.value}"
|
|
8132
|
+
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.`,
|
|
8276
8133
|
...nodeLoc(decl)
|
|
8277
8134
|
});
|
|
8278
8135
|
} else if (isUnpairedFitContentWidth(decl)) {
|
|
@@ -8337,7 +8194,7 @@ var check21 = {
|
|
|
8337
8194
|
for (const file of files) {
|
|
8338
8195
|
let css;
|
|
8339
8196
|
try {
|
|
8340
|
-
css = await
|
|
8197
|
+
css = await readFile16(file, "utf8");
|
|
8341
8198
|
} catch (err) {
|
|
8342
8199
|
results.push({
|
|
8343
8200
|
checkId: check21.id,
|
|
@@ -8364,12 +8221,12 @@ var check21 = {
|
|
|
8364
8221
|
registerCheck(check21);
|
|
8365
8222
|
|
|
8366
8223
|
// src/checks/source/css-ownership.ts
|
|
8367
|
-
import { readFile as
|
|
8224
|
+
import { readFile as readFile17 } from "node:fs/promises";
|
|
8368
8225
|
import postcss3 from "postcss";
|
|
8369
8226
|
import { parse as parseYaml3 } from "yaml";
|
|
8370
8227
|
var CONFIG_NAMES3 = [".gutterpress/css-contract.yaml", ".gutterpress/css-contract.yml"];
|
|
8371
8228
|
async function loadContract(configPath) {
|
|
8372
|
-
const raw = await
|
|
8229
|
+
const raw = await readFile17(configPath, "utf8");
|
|
8373
8230
|
const parsed = parseYaml3(raw);
|
|
8374
8231
|
if (parsed && typeof parsed === "object")
|
|
8375
8232
|
return parsed;
|
|
@@ -8520,7 +8377,7 @@ var check22 = {
|
|
|
8520
8377
|
continue;
|
|
8521
8378
|
let css;
|
|
8522
8379
|
try {
|
|
8523
|
-
css = await
|
|
8380
|
+
css = await readFile17(absFile, "utf8");
|
|
8524
8381
|
} catch {
|
|
8525
8382
|
continue;
|
|
8526
8383
|
}
|
|
@@ -8566,7 +8423,7 @@ import { existsSync as existsSync10 } from "node:fs";
|
|
|
8566
8423
|
import { dirname as dirname3, resolve as resolve6 } from "node:path";
|
|
8567
8424
|
|
|
8568
8425
|
// src/checks/source/local-ref-parser.ts
|
|
8569
|
-
import { readFile as
|
|
8426
|
+
import { readFile as readFile18 } from "node:fs/promises";
|
|
8570
8427
|
function newlineOffsets(content) {
|
|
8571
8428
|
const offsets = [];
|
|
8572
8429
|
for (let i = 0;i < content.length; i++)
|
|
@@ -8635,7 +8492,7 @@ async function* renderedLocalRefs(ctx, checkId, results) {
|
|
|
8635
8492
|
for (const file of files) {
|
|
8636
8493
|
let refs;
|
|
8637
8494
|
try {
|
|
8638
|
-
refs = collectRenderedLocalRefs(await
|
|
8495
|
+
refs = collectRenderedLocalRefs(await readFile18(file, "utf8"));
|
|
8639
8496
|
} catch {
|
|
8640
8497
|
results.push(inspectionFailed(checkId, `Could not read source file: ${file}`, { file }));
|
|
8641
8498
|
continue;
|
|
@@ -8986,7 +8843,7 @@ var check24 = {
|
|
|
8986
8843
|
registerCheck(check24);
|
|
8987
8844
|
|
|
8988
8845
|
// src/checks/source/accessibility-alt-text.ts
|
|
8989
|
-
import { readFile as
|
|
8846
|
+
import { readFile as readFile19 } from "node:fs/promises";
|
|
8990
8847
|
var check25 = {
|
|
8991
8848
|
id: "source.accessibility.alt-text",
|
|
8992
8849
|
name: "Image Alt Text",
|
|
@@ -9000,7 +8857,7 @@ var check25 = {
|
|
|
9000
8857
|
const results = [];
|
|
9001
8858
|
for (const file of files) {
|
|
9002
8859
|
try {
|
|
9003
|
-
const content = await
|
|
8860
|
+
const content = await readFile19(file, "utf8");
|
|
9004
8861
|
const lines = content.split(`
|
|
9005
8862
|
`);
|
|
9006
8863
|
let inFence = false;
|
|
@@ -9044,7 +8901,7 @@ function extractImageAlts(line) {
|
|
|
9044
8901
|
registerCheck(check25);
|
|
9045
8902
|
|
|
9046
8903
|
// src/checks/source/accessibility-heading-order.ts
|
|
9047
|
-
import { readFile as
|
|
8904
|
+
import { readFile as readFile20 } from "node:fs/promises";
|
|
9048
8905
|
var check26 = {
|
|
9049
8906
|
id: "source.accessibility.heading-order",
|
|
9050
8907
|
name: "Heading Order",
|
|
@@ -9058,7 +8915,7 @@ var check26 = {
|
|
|
9058
8915
|
const results = [];
|
|
9059
8916
|
for (const file of files) {
|
|
9060
8917
|
try {
|
|
9061
|
-
const content = await
|
|
8918
|
+
const content = await readFile20(file, "utf8");
|
|
9062
8919
|
const lines = content.split(`
|
|
9063
8920
|
`);
|
|
9064
8921
|
let inFence = false;
|
|
@@ -9100,7 +8957,7 @@ var check26 = {
|
|
|
9100
8957
|
registerCheck(check26);
|
|
9101
8958
|
|
|
9102
8959
|
// src/checks/source/layout-markers.ts
|
|
9103
|
-
import { readFile as
|
|
8960
|
+
import { readFile as readFile21 } from "node:fs/promises";
|
|
9104
8961
|
|
|
9105
8962
|
// src/lib/unknown-classes.ts
|
|
9106
8963
|
import postcss4 from "postcss";
|
|
@@ -9203,7 +9060,7 @@ async function collectKnownClasses(ctx, plugins) {
|
|
|
9203
9060
|
const sheets = (await collectStyleDependencies(ctx.inputDir, roots)).filter((f) => /\.css$/i.test(f));
|
|
9204
9061
|
for (const sheet of sheets) {
|
|
9205
9062
|
try {
|
|
9206
|
-
addCssClasses(await
|
|
9063
|
+
addCssClasses(await readFile21(sheet, "utf8"), names);
|
|
9207
9064
|
} catch {}
|
|
9208
9065
|
}
|
|
9209
9066
|
return names;
|
|
@@ -9227,7 +9084,7 @@ var check27 = {
|
|
|
9227
9084
|
const knownClasses = () => known ??= collectKnownClasses(ctx, plugins);
|
|
9228
9085
|
for (const file of files) {
|
|
9229
9086
|
try {
|
|
9230
|
-
const content = await
|
|
9087
|
+
const content = await readFile21(file, "utf8");
|
|
9231
9088
|
const env = {};
|
|
9232
9089
|
const tokens = md.parse(content, env);
|
|
9233
9090
|
md.renderer.render(tokens, md.options, env);
|
|
@@ -9267,7 +9124,7 @@ var check27 = {
|
|
|
9267
9124
|
registerCheck(check27);
|
|
9268
9125
|
|
|
9269
9126
|
// src/checks/source/merge-markers.ts
|
|
9270
|
-
import { readFile as
|
|
9127
|
+
import { readFile as readFile22 } from "node:fs/promises";
|
|
9271
9128
|
import path12 from "node:path";
|
|
9272
9129
|
|
|
9273
9130
|
// src/checks/asset/extensions.ts
|
|
@@ -9309,7 +9166,7 @@ var check28 = {
|
|
|
9309
9166
|
for (const file of textFiles) {
|
|
9310
9167
|
let content;
|
|
9311
9168
|
try {
|
|
9312
|
-
content = await
|
|
9169
|
+
content = await readFile22(file, "utf8");
|
|
9313
9170
|
} catch {
|
|
9314
9171
|
results.push(inspectionFailed(check28.id, `Could not read source file: ${file}`, { file }));
|
|
9315
9172
|
continue;
|
|
@@ -9369,7 +9226,7 @@ var check28 = {
|
|
|
9369
9226
|
registerCheck(check28);
|
|
9370
9227
|
|
|
9371
9228
|
// src/checks/source/characters.ts
|
|
9372
|
-
import { readFile as
|
|
9229
|
+
import { readFile as readFile23 } from "node:fs/promises";
|
|
9373
9230
|
|
|
9374
9231
|
// src/checks/source/character-table.ts
|
|
9375
9232
|
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");
|
|
@@ -9492,7 +9349,7 @@ var check29 = {
|
|
|
9492
9349
|
for (const file of (ctx.markdownFiles ?? []).slice().sort()) {
|
|
9493
9350
|
let content;
|
|
9494
9351
|
try {
|
|
9495
|
-
content = await
|
|
9352
|
+
content = await readFile23(file, "utf8");
|
|
9496
9353
|
} catch {
|
|
9497
9354
|
results.push(inspectionFailed(check29.id, `Could not read source file: ${file}`, { file }));
|
|
9498
9355
|
continue;
|
|
@@ -9532,16 +9389,16 @@ var check29 = {
|
|
|
9532
9389
|
registerCheck(check29);
|
|
9533
9390
|
|
|
9534
9391
|
// src/checks/asset/image-file-size.ts
|
|
9535
|
-
import { stat as
|
|
9392
|
+
import { stat as stat3 } from "node:fs/promises";
|
|
9536
9393
|
|
|
9537
9394
|
// src/lib/image-inspect.ts
|
|
9538
|
-
import { stat as
|
|
9395
|
+
import { stat as stat2, readFile as readFile24 } from "node:fs/promises";
|
|
9539
9396
|
var DEFAULT_DPI = 72;
|
|
9540
9397
|
var cache = new Map;
|
|
9541
9398
|
async function inspectImage(path13) {
|
|
9542
9399
|
let st;
|
|
9543
9400
|
try {
|
|
9544
|
-
st = await
|
|
9401
|
+
st = await stat2(path13);
|
|
9545
9402
|
} catch {
|
|
9546
9403
|
return null;
|
|
9547
9404
|
}
|
|
@@ -9550,7 +9407,7 @@ async function inspectImage(path13) {
|
|
|
9550
9407
|
return hit.info;
|
|
9551
9408
|
let info3 = null;
|
|
9552
9409
|
try {
|
|
9553
|
-
const buf = await
|
|
9410
|
+
const buf = await readFile24(path13);
|
|
9554
9411
|
info3 = parseImage(buf);
|
|
9555
9412
|
} catch {
|
|
9556
9413
|
info3 = null;
|
|
@@ -9772,7 +9629,7 @@ var check30 = {
|
|
|
9772
9629
|
const results = [];
|
|
9773
9630
|
for (const file of files) {
|
|
9774
9631
|
try {
|
|
9775
|
-
const info3 = await
|
|
9632
|
+
const info3 = await stat3(file);
|
|
9776
9633
|
if (info3.size > maxSize) {
|
|
9777
9634
|
const sizeMb = (info3.size / 1e6).toFixed(1);
|
|
9778
9635
|
const maxMb = (maxSize / 1e6).toFixed(1);
|
|
@@ -10110,7 +9967,7 @@ var check37 = {
|
|
|
10110
9967
|
registerCheck(check37);
|
|
10111
9968
|
|
|
10112
9969
|
// src/checks/heuristic/section-density.ts
|
|
10113
|
-
import { readFile as
|
|
9970
|
+
import { readFile as readFile25 } from "node:fs/promises";
|
|
10114
9971
|
var check38 = {
|
|
10115
9972
|
id: "heuristic.chunking.section-density",
|
|
10116
9973
|
name: "Section Density",
|
|
@@ -10127,7 +9984,7 @@ var check38 = {
|
|
|
10127
9984
|
const results = [];
|
|
10128
9985
|
for (const file of files) {
|
|
10129
9986
|
try {
|
|
10130
|
-
const content = await
|
|
9987
|
+
const content = await readFile25(file, "utf8");
|
|
10131
9988
|
const lines = content.split(`
|
|
10132
9989
|
`);
|
|
10133
9990
|
let currentSectionStart = 0;
|
|
@@ -10857,6 +10714,7 @@ async function renderBook(ctx) {
|
|
|
10857
10714
|
const htmlFile = await renderChaptersToFile(renderDir, workDir, {
|
|
10858
10715
|
title: config.title,
|
|
10859
10716
|
print: config.print,
|
|
10717
|
+
printArea: { ...config.page, preset: config.preset, spec: config.spec },
|
|
10860
10718
|
styles: config.styles,
|
|
10861
10719
|
files: config.source.files,
|
|
10862
10720
|
plugins,
|
|
@@ -11009,7 +10867,7 @@ class PdfOutput {
|
|
|
11009
10867
|
const rawPdf = pdfxMode ? path13.join(stage, "raw.pdf") : path13.resolve(pdfFile);
|
|
11010
10868
|
await fsp2.mkdir(path13.dirname(path13.resolve(pdfFile)), { recursive: true });
|
|
11011
10869
|
log.info("Rendering HTML to PDF via the Gutterpress engine (native Chromium pagination)");
|
|
11012
|
-
const { buildNativePdf } = await import("./engine-
|
|
10870
|
+
const { buildNativePdf } = await import("./engine-7ha27n2b.js");
|
|
11013
10871
|
const engineDiagnostics = await buildNativePdf(htmlFile, rawPdf, {
|
|
11014
10872
|
title: config.title,
|
|
11015
10873
|
author: config.authors.length > 0 ? config.authors.join(", ") : undefined,
|
|
@@ -11031,12 +10889,40 @@ class PdfOutput {
|
|
|
11031
10889
|
if (pdfxMode) {
|
|
11032
10890
|
const icc = opts.iccPath ?? config.pdfx.icc;
|
|
11033
10891
|
effectiveIccPath = await resolveIccProfile(icc, manifestDir, opts.iccPath);
|
|
11034
|
-
|
|
11035
|
-
|
|
10892
|
+
const rawBytes = await fsp2.readFile(rawPdf);
|
|
10893
|
+
const transparent = await transparentPages(rawBytes);
|
|
10894
|
+
const blankGradientPages = await findPostScriptShadingPages(rawBytes);
|
|
10895
|
+
const flattenedGradientPages = blankGradientPages.filter((n) => transparent.includes(n));
|
|
10896
|
+
const vectorGradientPages = blankGradientPages.filter((n) => !transparent.includes(n));
|
|
10897
|
+
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.";
|
|
10898
|
+
const pageList = (pages) => `Page${pages.length === 1 ? "" : "s"} ${pages.join(", ")}`;
|
|
10899
|
+
if (vectorGradientPages.length > 0) {
|
|
10900
|
+
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}`);
|
|
11036
10901
|
}
|
|
11037
|
-
|
|
11038
|
-
|
|
11039
|
-
|
|
10902
|
+
if (flattenedGradientPages.length > 0 && config.pdfx.transparency !== "preserve-text") {
|
|
10903
|
+
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}`);
|
|
10904
|
+
}
|
|
10905
|
+
const flattenPages = config.pdfx.flattenPages;
|
|
10906
|
+
if (transparent.length > 0 && config.pdfx.transparency === "preserve-text") {
|
|
10907
|
+
const { unsplittableTextReasons } = await import("./pdf-inspect-zdmy7qca.js");
|
|
10908
|
+
const reasons = await unsplittableTextReasons(rawBytes, transparent).catch((err) => {
|
|
10909
|
+
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.`);
|
|
10910
|
+
return null;
|
|
10911
|
+
});
|
|
10912
|
+
if (reasons) {
|
|
10913
|
+
const plan = planTransparentPages(transparent, reasons, flattenPages, blankGradientPages);
|
|
10914
|
+
await flattenTransparentPages(rawPdf, plan.split, stage, config.pdfx.rasterDpi);
|
|
10915
|
+
reportTransparentPlan(plan, pdfxMode, config.pdfx.rasterDpi ?? 300, pageList);
|
|
10916
|
+
}
|
|
10917
|
+
}
|
|
10918
|
+
const unused = flattenPages.filter((n) => !transparent.includes(n));
|
|
10919
|
+
if (flattenPages.length > 0 && config.pdfx.transparency !== "preserve-text") {
|
|
10920
|
+
log.warn("pdfx.flattenPages has no effect without pdfx.transparency: preserve-text.");
|
|
10921
|
+
} else if (unused.length > 0) {
|
|
10922
|
+
log.warn(`pdfx.flattenPages lists ${pageList(unused).toLowerCase()}, which ${unused.length === 1 ? "has" : "have"} no transparency (or do not exist): nothing to flatten there.`);
|
|
10923
|
+
}
|
|
10924
|
+
if (transparent.length > 0 && config.pdfx.transparency !== "preserve-text") {
|
|
10925
|
+
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).");
|
|
11040
10926
|
}
|
|
11041
10927
|
const shouldStrip = opts.stripAnnotations ?? config.pdfx.stripAnnotations;
|
|
11042
10928
|
shouldStripAnnotations = shouldStrip;
|
|
@@ -11079,7 +10965,10 @@ class PdfOutput {
|
|
|
11079
10965
|
resolvedFlavor: config.pdfx.flavor,
|
|
11080
10966
|
iccPath: effectiveIccPath,
|
|
11081
10967
|
stripAnnotations: shouldStripAnnotations,
|
|
11082
|
-
blackText: pdfxMode ? config.pdfx.blackText : null
|
|
10968
|
+
blackText: pdfxMode ? config.pdfx.blackText : null,
|
|
10969
|
+
transparency: pdfxMode ? config.pdfx.transparency : null,
|
|
10970
|
+
flattenPages: pdfxMode ? config.pdfx.flattenPages : null,
|
|
10971
|
+
rasterDpi: pdfxMode ? config.pdfx.rasterDpi ?? null : null
|
|
11083
10972
|
}
|
|
11084
10973
|
}, `Wrote: ${reportedPdf}`, { htmlPath: htmlFile, pdfPath: reportedPdf }, pdfName, engineDiagnostics);
|
|
11085
10974
|
} finally {
|
|
@@ -11116,11 +11005,40 @@ async function runBuild(opts) {
|
|
|
11116
11005
|
await fsp2.rm(ctx.workDir, { recursive: true, force: true });
|
|
11117
11006
|
}
|
|
11118
11007
|
}
|
|
11008
|
+
var FALLBACK_CAUSE = {
|
|
11009
|
+
listed: "listed in pdfx.flattenPages",
|
|
11010
|
+
"text-transparency": "text drawn with transparency or blending (opacity, mix-blend-mode, a soft mask, a translucent text-shadow); keep that text opaque",
|
|
11011
|
+
"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",
|
|
11012
|
+
"text-pattern-or-clip": 'text filled with a pattern or used as a clip (SVG fill="url(#…)", gradient text, background-clip: text)',
|
|
11013
|
+
gradient: "a repeating or conic gradient; use a linear or radial gradient, or a small tiled image"
|
|
11014
|
+
};
|
|
11015
|
+
function reportTransparentPlan({ split, artOnly, kept }, pdfxMode, dpi, pageList) {
|
|
11016
|
+
const one = (pages, singular, plural) => pages.length === 1 ? singular : plural;
|
|
11017
|
+
if (split.length > 0) {
|
|
11018
|
+
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.`);
|
|
11019
|
+
}
|
|
11020
|
+
if (artOnly.length > 0) {
|
|
11021
|
+
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).`);
|
|
11022
|
+
}
|
|
11023
|
+
if (kept.size > 0) {
|
|
11024
|
+
const pages = [...kept.keys()];
|
|
11025
|
+
const byCause = new Map;
|
|
11026
|
+
for (const [n, cause] of kept)
|
|
11027
|
+
byCause.set(cause, [...byCause.get(cause) ?? [], n]);
|
|
11028
|
+
const lines = [...byCause].map(([cause, ns]) => ` - ${one(ns, "page", "pages")} ${ns.join(", ")}: ${FALLBACK_CAUSE[cause]}`);
|
|
11029
|
+
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:
|
|
11030
|
+
` + lines.join(`
|
|
11031
|
+
`));
|
|
11032
|
+
}
|
|
11033
|
+
if (split.length === 0 && [...kept.values()].some((cause) => cause !== "listed")) {
|
|
11034
|
+
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).");
|
|
11035
|
+
}
|
|
11036
|
+
}
|
|
11119
11037
|
// src/preview/lifecycle.ts
|
|
11120
11038
|
import path16 from "path";
|
|
11121
11039
|
import { tmpdir } from "os";
|
|
11122
11040
|
import { randomBytes as randomBytes2 } from "crypto";
|
|
11123
|
-
import { readdir as readdir5, readFile as
|
|
11041
|
+
import { readdir as readdir5, readFile as readFile26, writeFile as writeFile6 } from "node:fs/promises";
|
|
11124
11042
|
|
|
11125
11043
|
// src/utils/file-utils.ts
|
|
11126
11044
|
import { promises as fs3 } from "fs";
|
|
@@ -11223,6 +11141,7 @@ async function renderPreviewBook(inputPath, config, opts) {
|
|
|
11223
11141
|
return renderChapters(inputPath, {
|
|
11224
11142
|
title: config.title ?? "Document",
|
|
11225
11143
|
print: config.print,
|
|
11144
|
+
printArea: config.printArea,
|
|
11226
11145
|
styles: config.styles,
|
|
11227
11146
|
files: opts.files,
|
|
11228
11147
|
plugins,
|
|
@@ -11237,19 +11156,8 @@ async function renderPreviewBook(inputPath, config, opts) {
|
|
|
11237
11156
|
}
|
|
11238
11157
|
});
|
|
11239
11158
|
}
|
|
11240
|
-
function injectPreviewScripts(html
|
|
11241
|
-
const
|
|
11242
|
-
width: page.width,
|
|
11243
|
-
height: page.height,
|
|
11244
|
-
bleed: page.bleed ?? 0,
|
|
11245
|
-
safe: page.safe ?? 0,
|
|
11246
|
-
artSafe: page.artSafe,
|
|
11247
|
-
preset: page.preset,
|
|
11248
|
-
spec: page.spec
|
|
11249
|
-
}) : "";
|
|
11250
|
-
const meta = area ? ` <meta name="gp-print-area" content='${area.replace(/&/g, "&").replace(/'/g, "'")}'>
|
|
11251
|
-
` : "";
|
|
11252
|
-
const scripts = meta + ` <script src="/engine/gutterpress-viewer.js"></script>
|
|
11159
|
+
function injectPreviewScripts(html) {
|
|
11160
|
+
const scripts = ` <script src="/engine/gutterpress-viewer.js"></script>
|
|
11253
11161
|
` + `<script src="/preview/scripts/preview-interface.js"></script>
|
|
11254
11162
|
` + `<script src="/preview/scripts/preview-bridge.js"></script>
|
|
11255
11163
|
`;
|
|
@@ -11264,7 +11172,10 @@ async function generateAndWriteHtml(inputPath, tempDir, config, cssAssets, image
|
|
|
11264
11172
|
}
|
|
11265
11173
|
const nextAssets = new Map;
|
|
11266
11174
|
const nextImageRefs = new Set;
|
|
11267
|
-
const html = await renderPreviewBook(inputPath,
|
|
11175
|
+
const html = await renderPreviewBook(inputPath, {
|
|
11176
|
+
...config,
|
|
11177
|
+
printArea: config.page && { ...config.page, preset: config.preset, spec: config.spec }
|
|
11178
|
+
}, {
|
|
11268
11179
|
files: config.source?.files ?? null,
|
|
11269
11180
|
onCssAssets: (copies) => {
|
|
11270
11181
|
for (const copy of copies)
|
|
@@ -11283,7 +11194,7 @@ async function generateAndWriteHtml(inputPath, tempDir, config, cssAssets, image
|
|
|
11283
11194
|
for (const ref of nextImageRefs)
|
|
11284
11195
|
imageRefs.add(ref);
|
|
11285
11196
|
}
|
|
11286
|
-
await fsp3.writeFile(path15.join(tempDir, BOOK_HTML_FILENAME), injectPreviewScripts(html
|
|
11197
|
+
await fsp3.writeFile(path15.join(tempDir, BOOK_HTML_FILENAME), injectPreviewScripts(html), "utf-8");
|
|
11287
11198
|
}
|
|
11288
11199
|
function isDotPathUnderRoot(candidatePath, root) {
|
|
11289
11200
|
const normalizedRoot = root.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
@@ -11681,7 +11592,7 @@ async function cleanupOrphanTempDirs() {
|
|
|
11681
11592
|
const dir = path16.join(TEMP_DIR_BASE, entry);
|
|
11682
11593
|
const pidFile = path16.join(dir, PID_FILE_NAME);
|
|
11683
11594
|
try {
|
|
11684
|
-
const raw = await
|
|
11595
|
+
const raw = await readFile26(pidFile, "utf8");
|
|
11685
11596
|
const pid = parseInt(raw.trim(), 10);
|
|
11686
11597
|
if (!isProcessAlive(pid)) {
|
|
11687
11598
|
debug(`Removing orphan temp dir ${dir} (pid ${pid} not alive)`);
|
|
@@ -11788,7 +11699,7 @@ function createServerState(inputPath, tempDir, config, options) {
|
|
|
11788
11699
|
import http from "node:http";
|
|
11789
11700
|
import net from "node:net";
|
|
11790
11701
|
import { createHash as createHash5, randomUUID as randomUUID3 } from "node:crypto";
|
|
11791
|
-
import { readFile as
|
|
11702
|
+
import { readFile as readFile27, stat as stat4 } from "node:fs/promises";
|
|
11792
11703
|
import path17 from "path";
|
|
11793
11704
|
import { WebSocket, WebSocketServer } from "ws";
|
|
11794
11705
|
|
|
@@ -11877,7 +11788,7 @@ async function findAvailablePort(startPort, host = "127.0.0.1") {
|
|
|
11877
11788
|
async function serveStatic(absPath, res, cacheControl = "no-store", extraHeaders = {}) {
|
|
11878
11789
|
let filePath = absPath;
|
|
11879
11790
|
try {
|
|
11880
|
-
const s = await
|
|
11791
|
+
const s = await stat4(filePath);
|
|
11881
11792
|
if (s.isDirectory())
|
|
11882
11793
|
filePath = path17.join(filePath, "index.html");
|
|
11883
11794
|
} catch {
|
|
@@ -11887,7 +11798,7 @@ async function serveStatic(absPath, res, cacheControl = "no-store", extraHeaders
|
|
|
11887
11798
|
}
|
|
11888
11799
|
let data;
|
|
11889
11800
|
try {
|
|
11890
|
-
data = await
|
|
11801
|
+
data = await readFile27(filePath);
|
|
11891
11802
|
} catch {
|
|
11892
11803
|
res.writeHead(404);
|
|
11893
11804
|
res.end("Not Found");
|
|
@@ -11916,7 +11827,7 @@ async function serveRevalidatedStatic(req, absPath, res, validators) {
|
|
|
11916
11827
|
}
|
|
11917
11828
|
let fileStat;
|
|
11918
11829
|
try {
|
|
11919
|
-
fileStat = await
|
|
11830
|
+
fileStat = await stat4(absPath, { bigint: true });
|
|
11920
11831
|
} catch {
|
|
11921
11832
|
await serveStatic(absPath, res);
|
|
11922
11833
|
return;
|
|
@@ -11936,7 +11847,7 @@ async function serveRevalidatedStatic(req, absPath, res, validators) {
|
|
|
11936
11847
|
let data;
|
|
11937
11848
|
if (!validator || validator.stamp !== stamp) {
|
|
11938
11849
|
try {
|
|
11939
|
-
data = await
|
|
11850
|
+
data = await readFile27(absPath);
|
|
11940
11851
|
} catch {
|
|
11941
11852
|
await serveStatic(absPath, res);
|
|
11942
11853
|
return;
|
|
@@ -11964,7 +11875,7 @@ async function isMissingReferencedImage(pathname, absPath, refs) {
|
|
|
11964
11875
|
if (!refs.has(imageRefKey(pathname)))
|
|
11965
11876
|
return false;
|
|
11966
11877
|
try {
|
|
11967
|
-
await
|
|
11878
|
+
await stat4(absPath);
|
|
11968
11879
|
return false;
|
|
11969
11880
|
} catch (err) {
|
|
11970
11881
|
return err?.code === "ENOENT";
|
|
@@ -12248,7 +12159,7 @@ async function startPreviewServer(options) {
|
|
|
12248
12159
|
import { platform, arch, release } from "node:os";
|
|
12249
12160
|
|
|
12250
12161
|
// src/lib/remote-auth/token-store.ts
|
|
12251
|
-
import { chmod, mkdir as mkdir7, readFile as
|
|
12162
|
+
import { chmod, mkdir as mkdir7, readFile as readFile28, rename as rename4, writeFile as writeFile7 } from "node:fs/promises";
|
|
12252
12163
|
import os3 from "node:os";
|
|
12253
12164
|
import path18 from "node:path";
|
|
12254
12165
|
function credentialHostKey(hostOrUrl) {
|
|
@@ -12292,7 +12203,7 @@ class FileTokenStore {
|
|
|
12292
12203
|
async read() {
|
|
12293
12204
|
let raw;
|
|
12294
12205
|
try {
|
|
12295
|
-
raw = await
|
|
12206
|
+
raw = await readFile28(this.filePath, "utf8");
|
|
12296
12207
|
} catch (e) {
|
|
12297
12208
|
if (e?.code === "ENOENT") {
|
|
12298
12209
|
return { version: 1, credentials: {} };
|
|
@@ -12492,13 +12403,13 @@ async function getSystemDiagnostics() {
|
|
|
12492
12403
|
};
|
|
12493
12404
|
}
|
|
12494
12405
|
// src/lib/project-scaffold.ts
|
|
12495
|
-
import { access, copyFile, cp as cp2, mkdir as mkdir9, readdir as readdir6, readFile as
|
|
12406
|
+
import { access, copyFile, cp as cp2, mkdir as mkdir9, readdir as readdir6, readFile as readFile30, stat as stat5, writeFile as writeFile9 } from "node:fs/promises";
|
|
12496
12407
|
import { constants as FS, existsSync as existsSync14 } from "node:fs";
|
|
12497
12408
|
import path20 from "node:path";
|
|
12498
12409
|
|
|
12499
12410
|
// src/lib/page-size.ts
|
|
12500
12411
|
import { existsSync as existsSync13 } from "node:fs";
|
|
12501
|
-
import { mkdir as mkdir8, readFile as
|
|
12412
|
+
import { mkdir as mkdir8, readFile as readFile29, writeFile as writeFile8 } from "node:fs/promises";
|
|
12502
12413
|
import path19 from "node:path";
|
|
12503
12414
|
import postcss5 from "postcss";
|
|
12504
12415
|
import { Scalar as Scalar2 } from "yaml";
|
|
@@ -12603,7 +12514,7 @@ var relDisplay2 = (projectDir, abs) => path19.relative(projectDir, abs).split(pa
|
|
|
12603
12514
|
async function findCssSize(projectDir, sheets) {
|
|
12604
12515
|
let found = null;
|
|
12605
12516
|
for (const file of sheets) {
|
|
12606
|
-
const size = readPageSizeFromCss(await
|
|
12517
|
+
const size = readPageSizeFromCss(await readFile29(file, "utf8"));
|
|
12607
12518
|
if (size)
|
|
12608
12519
|
found = { file, size };
|
|
12609
12520
|
}
|
|
@@ -12630,7 +12541,7 @@ async function setPageSetup(projectDir, choice) {
|
|
|
12630
12541
|
const found = await findCssSize(projectDir, sheets);
|
|
12631
12542
|
const newSheet = path19.join(projectDir, "styles", "book.css");
|
|
12632
12543
|
const target = found?.file ?? sheets[sheets.length - 1] ?? newSheet;
|
|
12633
|
-
const before = existsSync13(target) ? await
|
|
12544
|
+
const before = existsSync13(target) ? await readFile29(target, "utf8") : "";
|
|
12634
12545
|
let after;
|
|
12635
12546
|
try {
|
|
12636
12547
|
after = setPageSizeInCss(before, size);
|
|
@@ -12839,7 +12750,7 @@ async function adoptFolder(options) {
|
|
|
12839
12750
|
}
|
|
12840
12751
|
let st;
|
|
12841
12752
|
try {
|
|
12842
|
-
st = await
|
|
12753
|
+
st = await stat5(dir);
|
|
12843
12754
|
} catch {
|
|
12844
12755
|
throw new CreateProjectErrorImpl("scaffold-io", `Folder not found: ${dir}`);
|
|
12845
12756
|
}
|
|
@@ -12920,7 +12831,7 @@ styles:
|
|
|
12920
12831
|
async function firstSourceFile(manifestPath) {
|
|
12921
12832
|
let text;
|
|
12922
12833
|
try {
|
|
12923
|
-
text = await
|
|
12834
|
+
text = await readFile30(manifestPath, "utf8");
|
|
12924
12835
|
} catch {
|
|
12925
12836
|
return;
|
|
12926
12837
|
}
|
|
@@ -12932,14 +12843,14 @@ async function firstSourceFile(manifestPath) {
|
|
|
12932
12843
|
return m ? m[1].trim() : undefined;
|
|
12933
12844
|
}
|
|
12934
12845
|
async function fillTemplateFile(filePath, substitutions) {
|
|
12935
|
-
let text = await
|
|
12846
|
+
let text = await readFile30(filePath, "utf8");
|
|
12936
12847
|
for (const [token, value] of Object.entries(substitutions)) {
|
|
12937
12848
|
text = text.split(token).join(value);
|
|
12938
12849
|
}
|
|
12939
12850
|
await writeFile9(filePath, text, "utf8");
|
|
12940
12851
|
}
|
|
12941
12852
|
// src/lib/extension-scaffold.ts
|
|
12942
|
-
import { access as access2, mkdir as mkdir10, readFile as
|
|
12853
|
+
import { access as access2, mkdir as mkdir10, readFile as readFile31, writeFile as writeFile10 } from "node:fs/promises";
|
|
12943
12854
|
import { constants as FS2 } from "node:fs";
|
|
12944
12855
|
import path21 from "node:path";
|
|
12945
12856
|
var EXTENSION_KINDS = ["plugin", "theme"];
|
|
@@ -13056,7 +12967,7 @@ async function scaffoldExtension(options) {
|
|
|
13056
12967
|
const src = await getAssetPath(`extension-templates/${kind}/${assetName}`);
|
|
13057
12968
|
const dest = path21.join(extensionDir, relDest);
|
|
13058
12969
|
await mkdir10(path21.dirname(dest), { recursive: true });
|
|
13059
|
-
const text = await
|
|
12970
|
+
const text = await readFile31(src, "utf8");
|
|
13060
12971
|
const table = relDest.endsWith(".json") ? jsonSafe : plain;
|
|
13061
12972
|
await writeFile10(dest, substitute(text, table), "utf8");
|
|
13062
12973
|
written.push(relDest);
|
|
@@ -13082,7 +12993,7 @@ function substitute(text, table) {
|
|
|
13082
12993
|
return out;
|
|
13083
12994
|
}
|
|
13084
12995
|
// src/lib/project-templates.ts
|
|
13085
|
-
import { cp as cp3, mkdir as mkdir11, readFile as
|
|
12996
|
+
import { cp as cp3, mkdir as mkdir11, readFile as readFile32, readdir as readdir7, stat as stat6, writeFile as writeFile11 } from "node:fs/promises";
|
|
13086
12997
|
import { constants as FS3, existsSync as existsSync15 } from "node:fs";
|
|
13087
12998
|
import { access as access3 } from "node:fs/promises";
|
|
13088
12999
|
import path22 from "node:path";
|
|
@@ -13094,7 +13005,7 @@ var BUILT_IN_TEMPLATE_IDS = [
|
|
|
13094
13005
|
];
|
|
13095
13006
|
async function readTemplateChoices(manifestPath) {
|
|
13096
13007
|
try {
|
|
13097
|
-
const text = await
|
|
13008
|
+
const text = await readFile32(manifestPath, "utf8");
|
|
13098
13009
|
const doc = parseDocument2(text);
|
|
13099
13010
|
const out = {};
|
|
13100
13011
|
const preset = doc.get("preset");
|
|
@@ -13276,7 +13187,7 @@ async function saveProjectAsTemplate(options) {
|
|
|
13276
13187
|
async function retokeniseManifest(manifestPath) {
|
|
13277
13188
|
let text;
|
|
13278
13189
|
try {
|
|
13279
|
-
text = await
|
|
13190
|
+
text = await readFile32(manifestPath, "utf8");
|
|
13280
13191
|
} catch {
|
|
13281
13192
|
return;
|
|
13282
13193
|
}
|
|
@@ -13297,7 +13208,7 @@ async function listCustomTemplates(templatesRoot) {
|
|
|
13297
13208
|
const dir = path22.join(templatesRoot, entry.name);
|
|
13298
13209
|
let label = prettify(entry.name);
|
|
13299
13210
|
try {
|
|
13300
|
-
const meta = JSON.parse(await
|
|
13211
|
+
const meta = JSON.parse(await readFile32(path22.join(dir, TEMPLATE_META_FILE), "utf8"));
|
|
13301
13212
|
if (typeof meta.label === "string" && meta.label)
|
|
13302
13213
|
label = meta.label;
|
|
13303
13214
|
} catch {}
|
|
@@ -13315,7 +13226,7 @@ async function listCustomTemplates(templatesRoot) {
|
|
|
13315
13226
|
}
|
|
13316
13227
|
async function importTemplateFromFolder(options) {
|
|
13317
13228
|
const { sourceDir, templatesRoot } = options;
|
|
13318
|
-
const srcStat = await
|
|
13229
|
+
const srcStat = await stat6(sourceDir);
|
|
13319
13230
|
if (!srcStat.isDirectory()) {
|
|
13320
13231
|
throw new Error("The chosen path is not a folder.");
|
|
13321
13232
|
}
|
|
@@ -13323,7 +13234,7 @@ async function importTemplateFromFolder(options) {
|
|
|
13323
13234
|
return saveProjectAsTemplate({ projectDir: sourceDir, name, templatesRoot });
|
|
13324
13235
|
}
|
|
13325
13236
|
// src/lib/snippets.ts
|
|
13326
|
-
import { readdir as readdir8, readFile as
|
|
13237
|
+
import { readdir as readdir8, readFile as readFile33, writeFile as writeFile12, mkdir as mkdir12, rm as rm4 } from "node:fs/promises";
|
|
13327
13238
|
import path23 from "node:path";
|
|
13328
13239
|
var SNIPPETS_DIR = "snippets";
|
|
13329
13240
|
var LEVEL_RANK = { project: 0, extension: 1, core: 2 };
|
|
@@ -13364,7 +13275,7 @@ async function scanSnippetFiles(dir) {
|
|
|
13364
13275
|
continue;
|
|
13365
13276
|
let body = "";
|
|
13366
13277
|
try {
|
|
13367
|
-
body = await
|
|
13278
|
+
body = await readFile33(path23.join(dir, fileName), "utf8");
|
|
13368
13279
|
} catch {
|
|
13369
13280
|
continue;
|
|
13370
13281
|
}
|
|
@@ -13453,7 +13364,7 @@ async function collectLibrary(projectDir) {
|
|
|
13453
13364
|
listed.component = name;
|
|
13454
13365
|
continue;
|
|
13455
13366
|
}
|
|
13456
|
-
const body = await
|
|
13367
|
+
const body = await readFile33(path23.join(entry.dir, rel), "utf8").catch(() => null);
|
|
13457
13368
|
if (body === null)
|
|
13458
13369
|
continue;
|
|
13459
13370
|
snippets2.push({
|
|
@@ -13522,7 +13433,7 @@ async function listLocationVariants(projectDir) {
|
|
|
13522
13433
|
}
|
|
13523
13434
|
// src/lib/extension-import.ts
|
|
13524
13435
|
import { existsSync as existsSync16 } from "node:fs";
|
|
13525
|
-
import { cp as cp4, mkdir as mkdir13, mkdtemp as mkdtemp2, readFile as
|
|
13436
|
+
import { cp as cp4, mkdir as mkdir13, mkdtemp as mkdtemp2, readFile as readFile34, rm as rm5, writeFile as writeFile13 } from "node:fs/promises";
|
|
13526
13437
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
13527
13438
|
import path24 from "node:path";
|
|
13528
13439
|
import { unzipSync } from "fflate";
|
|
@@ -13595,7 +13506,7 @@ async function finalizeExtensionImport(projectDir, sourceDir, relPaths, fallback
|
|
|
13595
13506
|
if (!existsSync16(cssPath)) {
|
|
13596
13507
|
throw new Error("A theme must contain a theme.css file.");
|
|
13597
13508
|
}
|
|
13598
|
-
const css = await
|
|
13509
|
+
const css = await readFile34(cssPath, "utf8");
|
|
13599
13510
|
const { reject, warnings: printFindings } = classifyThemeCssFindings(checkCss(css, "theme.css"));
|
|
13600
13511
|
if (reject) {
|
|
13601
13512
|
throw new Error(`theme.css could not be parsed — ${reject.message}`);
|
|
@@ -13623,7 +13534,7 @@ async function finalizeExtensionImport(projectDir, sourceDir, relPaths, fallback
|
|
|
13623
13534
|
for (let i = 0;i < extraSheets.length; i++) {
|
|
13624
13535
|
const rel = extraSheets[i];
|
|
13625
13536
|
const sheetPath = extraSheetPaths[i];
|
|
13626
|
-
const sheetCss = await
|
|
13537
|
+
const sheetCss = await readFile34(sheetPath, "utf8");
|
|
13627
13538
|
const { reject: sheetReject, warnings: sheetFindings } = classifyThemeCssFindings(checkCss(sheetCss, rel));
|
|
13628
13539
|
if (sheetReject) {
|
|
13629
13540
|
throw new Error(`${rel} could not be parsed — ${sheetReject.message}`);
|
|
@@ -13656,7 +13567,7 @@ async function completeLandedManifest(dest, id, meta, metaExists) {
|
|
|
13656
13567
|
let pkg = {};
|
|
13657
13568
|
if (metaExists) {
|
|
13658
13569
|
try {
|
|
13659
|
-
const parsed = JSON.parse(await
|
|
13570
|
+
const parsed = JSON.parse(await readFile34(file, "utf8"));
|
|
13660
13571
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
13661
13572
|
pkg = parsed;
|
|
13662
13573
|
}
|
|
@@ -13758,11 +13669,11 @@ async function importExtensionFromCssText(projectDir, css, name) {
|
|
|
13758
13669
|
async function importExtensionFromFile(projectDir, filePath) {
|
|
13759
13670
|
const ext = path24.extname(filePath).toLowerCase();
|
|
13760
13671
|
if (ext === ".zip") {
|
|
13761
|
-
const buf = await
|
|
13672
|
+
const buf = await readFile34(filePath);
|
|
13762
13673
|
return importExtensionFromZip(projectDir, new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength));
|
|
13763
13674
|
}
|
|
13764
13675
|
if (ext === ".css") {
|
|
13765
|
-
const css = await
|
|
13676
|
+
const css = await readFile34(filePath, "utf8");
|
|
13766
13677
|
return importExtensionFromCssText(projectDir, css, prettify(path24.basename(filePath, ".css")));
|
|
13767
13678
|
}
|
|
13768
13679
|
throw new Error("Choose a .zip extension package or a .css stylesheet.");
|
|
@@ -16143,7 +16054,7 @@ async function scorchedEarth(options) {
|
|
|
16143
16054
|
}
|
|
16144
16055
|
}
|
|
16145
16056
|
// src/lib/publish/run-publish.ts
|
|
16146
|
-
import { readdir as readdir12, stat as
|
|
16057
|
+
import { readdir as readdir12, stat as stat11 } from "node:fs/promises";
|
|
16147
16058
|
import path33 from "node:path";
|
|
16148
16059
|
|
|
16149
16060
|
// src/lib/publish/command-runner.ts
|
|
@@ -16374,7 +16285,7 @@ var drivethrurpgProvider = {
|
|
|
16374
16285
|
};
|
|
16375
16286
|
|
|
16376
16287
|
// src/lib/publish/providers/gdrive.ts
|
|
16377
|
-
import { mkdtemp as mkdtemp3, readFile as
|
|
16288
|
+
import { mkdtemp as mkdtemp3, readFile as readFile35, readdir as readdir11, rm as rm9, stat as stat8, writeFile as writeFile16 } from "node:fs/promises";
|
|
16378
16289
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
16379
16290
|
import path30 from "node:path";
|
|
16380
16291
|
import { Zip, ZipDeflate } from "fflate";
|
|
@@ -16766,12 +16677,12 @@ async function collectZipEntries(root, dir, out, onWarn) {
|
|
|
16766
16677
|
await collectZipEntries(root, full, out, onWarn);
|
|
16767
16678
|
} else if (entry.isFile()) {
|
|
16768
16679
|
const rel = path30.relative(root, full).split(path30.sep).join("/");
|
|
16769
|
-
out[rel] = await
|
|
16680
|
+
out[rel] = await readFile35(full);
|
|
16770
16681
|
} else if (entry.isSymbolicLink()) {
|
|
16771
|
-
const resolved = await
|
|
16682
|
+
const resolved = await stat8(full).catch(() => null);
|
|
16772
16683
|
if (resolved?.isFile()) {
|
|
16773
16684
|
const rel = path30.relative(root, full).split(path30.sep).join("/");
|
|
16774
|
-
out[rel] = await
|
|
16685
|
+
out[rel] = await readFile35(full);
|
|
16775
16686
|
} else if (resolved?.isDirectory()) {
|
|
16776
16687
|
await collectZipEntries(root, full, out, onWarn);
|
|
16777
16688
|
} else {
|
|
@@ -16841,7 +16752,7 @@ var gdriveProvider = {
|
|
|
16841
16752
|
cleanup: async () => {}
|
|
16842
16753
|
};
|
|
16843
16754
|
try {
|
|
16844
|
-
const artifactStat = await
|
|
16755
|
+
const artifactStat = await stat8(source.filePath);
|
|
16845
16756
|
const about = await driveAbout(fetchImpl, accessToken);
|
|
16846
16757
|
if (about.quota.limitBytes != null && about.quota.freeBytes != null) {
|
|
16847
16758
|
if (artifactStat.size > about.quota.freeBytes) {
|
|
@@ -16886,7 +16797,7 @@ var gdriveProvider = {
|
|
|
16886
16797
|
};
|
|
16887
16798
|
|
|
16888
16799
|
// src/lib/publish/butler.ts
|
|
16889
|
-
import { chmod as chmod2, mkdir as mkdir19, stat as
|
|
16800
|
+
import { chmod as chmod2, mkdir as mkdir19, stat as stat9, writeFile as writeFile17 } from "node:fs/promises";
|
|
16890
16801
|
import path31 from "node:path";
|
|
16891
16802
|
import { unzipSync as unzipSync2 } from "fflate";
|
|
16892
16803
|
var BUTLER_DOWNLOAD_TIMEOUT_MS = 300000;
|
|
@@ -16907,7 +16818,7 @@ function butlerBinaryName(platform2 = process.platform) {
|
|
|
16907
16818
|
}
|
|
16908
16819
|
async function fileExists2(p) {
|
|
16909
16820
|
try {
|
|
16910
|
-
return (await
|
|
16821
|
+
return (await stat9(p)).isFile();
|
|
16911
16822
|
} catch {
|
|
16912
16823
|
return false;
|
|
16913
16824
|
}
|
|
@@ -17150,7 +17061,7 @@ var kdpProvider = {
|
|
|
17150
17061
|
};
|
|
17151
17062
|
|
|
17152
17063
|
// src/lib/publish/providers/local-folder.ts
|
|
17153
|
-
import { cp as cp7, mkdir as mkdir20, stat as
|
|
17064
|
+
import { cp as cp7, mkdir as mkdir20, stat as stat10 } from "node:fs/promises";
|
|
17154
17065
|
import path32 from "node:path";
|
|
17155
17066
|
var LOCAL_PUBLISH_DEFAULT_DIR = "dist";
|
|
17156
17067
|
var info8 = {
|
|
@@ -17177,7 +17088,7 @@ var localFolderProvider = {
|
|
|
17177
17088
|
async preflight(req) {
|
|
17178
17089
|
const dir = localPublishDir(req);
|
|
17179
17090
|
try {
|
|
17180
|
-
const s = await
|
|
17091
|
+
const s = await stat10(dir);
|
|
17181
17092
|
if (!s.isDirectory()) {
|
|
17182
17093
|
return [
|
|
17183
17094
|
{ severity: "error", id: "local/not-a-folder", message: `${dir} exists but is not a folder.` }
|
|
@@ -17472,7 +17383,7 @@ var PDF_HINT = "Build the PDF first (gutterpress build, or export it from the ap
|
|
|
17472
17383
|
var HTML_HINT = "Build the website export first (gutterpress build --format html).";
|
|
17473
17384
|
async function artifactIssues(artifact) {
|
|
17474
17385
|
try {
|
|
17475
|
-
const s = await
|
|
17386
|
+
const s = await stat11(artifact.path);
|
|
17476
17387
|
if (artifact.format === "pdf" && !s.isFile()) {
|
|
17477
17388
|
return [
|
|
17478
17389
|
{
|
|
@@ -17518,7 +17429,7 @@ async function artifactIssues(artifact) {
|
|
|
17518
17429
|
var BUILD_FINGERPRINT_FILENAME = "build-fingerprint.json";
|
|
17519
17430
|
async function htmlDirIssues(dir) {
|
|
17520
17431
|
const issues = [];
|
|
17521
|
-
const isThere = async (rel) =>
|
|
17432
|
+
const isThere = async (rel) => stat11(path33.join(dir, rel)).then(() => true, () => false);
|
|
17522
17433
|
if (!await isThere(BOOK_HTML)) {
|
|
17523
17434
|
issues.push({
|
|
17524
17435
|
severity: "error",
|
|
@@ -17637,7 +17548,7 @@ async function disconnectPublishCredential(key, deps, options = {}) {
|
|
|
17637
17548
|
}
|
|
17638
17549
|
}
|
|
17639
17550
|
// src/lib/publish/selections.ts
|
|
17640
|
-
import { chmod as chmod3, mkdir as mkdir21, readFile as
|
|
17551
|
+
import { chmod as chmod3, mkdir as mkdir21, readFile as readFile36, writeFile as writeFile18 } from "node:fs/promises";
|
|
17641
17552
|
import path34 from "node:path";
|
|
17642
17553
|
class PublishSelectionsStore {
|
|
17643
17554
|
filePath;
|
|
@@ -17647,7 +17558,7 @@ class PublishSelectionsStore {
|
|
|
17647
17558
|
}
|
|
17648
17559
|
async read() {
|
|
17649
17560
|
try {
|
|
17650
|
-
const raw = await
|
|
17561
|
+
const raw = await readFile36(this.filePath, "utf8");
|
|
17651
17562
|
const parsed = JSON.parse(raw);
|
|
17652
17563
|
if (parsed && typeof parsed === "object") {
|
|
17653
17564
|
return {
|