gutterpress 0.11.20-alpha.2 → 0.11.20-alpha.3
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-a8ycsg80.js} +5 -4
- package/dist/{cli-zacevwcy.js → cli-9k2tb493.js} +181 -431
- package/dist/{cli-7z29z4wz.js → cli-hn9pk0hp.js} +1 -1
- package/dist/cli-sth219v1.js +418 -0
- package/dist/{cli-j802s31j.js → cli-x4p99w8d.js} +2 -2
- package/dist/{cli-gh0ym80r.js → cli-y9bcya7r.js} +121 -20
- package/dist/cli.js +12 -12
- package/dist/{doctor-fe7tcs4v.js → doctor-wbjkrcpc.js} +2 -2
- package/dist/{engine-yax79k9m.js → engine-fdtv01a2.js} +2 -2
- package/dist/{engine-9xb1ky8d.js → engine-yxnnp3hx.js} +1 -1
- package/dist/{ext-ahwxt6gv.js → ext-pesyrs68.js} +5 -4
- package/dist/{gutterpress-viewer-retj6ym2.js → gutterpress-viewer-1yse8cx3.js} +12 -4
- package/dist/{index-6xwtb7cw.js → index-r87y7wzw.js} +1 -1
- package/dist/index-sth219v1.js +418 -0
- package/dist/{index-razpty47.js → index-tjvrchxj.js} +297 -448
- package/dist/{index-3nr5rzzp.js → index-zagagnwq.js} +2 -2
- package/dist/index.js +4 -3
- package/dist/lib/build-fingerprint.d.ts +8 -0
- package/dist/lib/ghostscript.d.ts +70 -16
- package/dist/lib/pdf-inspect.d.ts +45 -0
- package/dist/{manifest.schema-74s1ykyv.json → manifest.schema-c9x8912a.json} +13 -1
- package/dist/{new-ftd4fec4.js → new-8yah8z91.js} +5 -4
- package/dist/pdf-inspect-zdmy7qca.js +35 -0
- package/dist/{preflight-8sqarcsr.js → preflight-8ccx4kdc.js} +5 -4
- package/dist/{preview-q76xn95h.js → preview-w7v9w36q.js} +5 -4
- package/dist/{publish-7gdy6gbf.js → publish-g5nh5myh.js} +5 -4
- package/dist/schema/manifest.types.d.ts +20 -2
- package/dist/test-helpers/testkit.d.ts +2 -2
- package/dist/{validate-e3ryegce.js → validate-1yh59x0x.js} +5 -4
- package/package.json +1 -1
|
@@ -9,7 +9,20 @@ import {
|
|
|
9
9
|
getAssetsDir,
|
|
10
10
|
lastPageMode,
|
|
11
11
|
parseSize
|
|
12
|
-
} from "./index-
|
|
12
|
+
} from "./index-zagagnwq.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)}.`);
|
|
@@ -5767,8 +5792,8 @@ async function resolveGhostscript(targetPlatform = process.platform, env = proce
|
|
|
5767
5792
|
}
|
|
5768
5793
|
return targetPlatform === "win32" ? findWindowsGhostscriptInstall(env) : undefined;
|
|
5769
5794
|
}
|
|
5770
|
-
async function
|
|
5771
|
-
const { PDFDocument, PDFDict, PDFName, PDFNumber, PDFRawStream, PDFRef } = await import("pdf-lib");
|
|
5795
|
+
async function transparentPages(pdfBytes) {
|
|
5796
|
+
const { PDFDocument, PDFDict, PDFName, PDFNumber, PDFRawStream, PDFArray, PDFRef } = await import("pdf-lib");
|
|
5772
5797
|
let doc;
|
|
5773
5798
|
try {
|
|
5774
5799
|
doc = await PDFDocument.load(pdfBytes, {
|
|
@@ -5776,36 +5801,64 @@ async function hasLiveTransparency(pdfBytes) {
|
|
|
5776
5801
|
throwOnInvalidObject: false
|
|
5777
5802
|
});
|
|
5778
5803
|
} catch {
|
|
5779
|
-
return
|
|
5804
|
+
return [];
|
|
5780
5805
|
}
|
|
5781
5806
|
const ctx = doc.context;
|
|
5782
|
-
const
|
|
5783
|
-
|
|
5784
|
-
|
|
5785
|
-
if (!dict)
|
|
5786
|
-
continue;
|
|
5807
|
+
const SKIP = new Set(["Parent", "Font", "Annots"]);
|
|
5808
|
+
const isSet = (v) => v !== undefined && String(v) !== "/None";
|
|
5809
|
+
const dictHasTransparency = (dict) => {
|
|
5787
5810
|
const smask = dict.get(PDFName.of("SMask"));
|
|
5788
5811
|
const subtype = String(dict.get(PDFName.of("Subtype")) ?? "");
|
|
5789
5812
|
const type = String(dict.get(PDFName.of("Type")) ?? "");
|
|
5790
|
-
if (subtype === "/Image" &&
|
|
5813
|
+
if (subtype === "/Image" && isSet(smask))
|
|
5791
5814
|
return true;
|
|
5792
|
-
if (type === "/ExtGState") {
|
|
5793
|
-
if (
|
|
5815
|
+
if (type === "/ExtGState" || dict.has(PDFName.of("ca")) || dict.has(PDFName.of("BM"))) {
|
|
5816
|
+
if (isSet(smask))
|
|
5794
5817
|
return true;
|
|
5795
5818
|
for (const key of ["ca", "CA"]) {
|
|
5796
|
-
const alpha = dict.get(PDFName.of(key));
|
|
5819
|
+
const alpha = ctx.lookup(dict.get(PDFName.of(key)));
|
|
5797
5820
|
if (alpha instanceof PDFNumber && alpha.asNumber() < 1)
|
|
5798
5821
|
return true;
|
|
5799
5822
|
}
|
|
5823
|
+
const bm = ctx.lookup(dict.get(PDFName.of("BM")));
|
|
5824
|
+
const mode = bm instanceof PDFArray ? bm.get(0) : bm;
|
|
5825
|
+
if (mode && !["/Normal", "/Compatible"].includes(String(mode)))
|
|
5826
|
+
return true;
|
|
5800
5827
|
}
|
|
5801
|
-
const group = dict.get(PDFName.of("Group"));
|
|
5802
|
-
|
|
5803
|
-
|
|
5804
|
-
|
|
5828
|
+
const group = ctx.lookup(dict.get(PDFName.of("Group")));
|
|
5829
|
+
return group instanceof PDFDict && String(group.get(PDFName.of("S"))) === "/Transparency";
|
|
5830
|
+
};
|
|
5831
|
+
const reaches = (root) => {
|
|
5832
|
+
const seen = new Set;
|
|
5833
|
+
const stack = [root];
|
|
5834
|
+
while (stack.length) {
|
|
5835
|
+
const node = stack.pop();
|
|
5836
|
+
const obj = node instanceof PDFRef ? ctx.lookup(node) : node;
|
|
5837
|
+
if (!obj || seen.has(obj))
|
|
5838
|
+
continue;
|
|
5839
|
+
seen.add(obj);
|
|
5840
|
+
if (obj instanceof PDFArray) {
|
|
5841
|
+
stack.push(...obj.asArray());
|
|
5842
|
+
continue;
|
|
5843
|
+
}
|
|
5844
|
+
const dict = obj instanceof PDFRawStream ? obj.dict : obj instanceof PDFDict ? obj : undefined;
|
|
5845
|
+
if (!dict)
|
|
5846
|
+
continue;
|
|
5847
|
+
if (dictHasTransparency(dict))
|
|
5805
5848
|
return true;
|
|
5849
|
+
for (const [key, value] of dict.entries()) {
|
|
5850
|
+
if (!SKIP.has(key.asString().slice(1)))
|
|
5851
|
+
stack.push(value);
|
|
5852
|
+
}
|
|
5806
5853
|
}
|
|
5807
|
-
|
|
5808
|
-
|
|
5854
|
+
return false;
|
|
5855
|
+
};
|
|
5856
|
+
const pages = [];
|
|
5857
|
+
doc.getPages().forEach((page, i) => {
|
|
5858
|
+
if (reaches(page.node))
|
|
5859
|
+
pages.push(i + 1);
|
|
5860
|
+
});
|
|
5861
|
+
return pages;
|
|
5809
5862
|
}
|
|
5810
5863
|
async function findPostScriptShadingPages(pdfBytes) {
|
|
5811
5864
|
const { PDFDocument, PDFDict, PDFName, PDFNumber, PDFRawStream, PDFRef } = await import("pdf-lib");
|
|
@@ -5876,6 +5929,75 @@ async function stripAnnotations(pdfPath, stagingDir) {
|
|
|
5876
5929
|
const out = await doc.save();
|
|
5877
5930
|
await writeFile3(pdfPath, out);
|
|
5878
5931
|
}
|
|
5932
|
+
function planTransparentPages(transparent, reasons, flattenPages, gradientPages) {
|
|
5933
|
+
const split = [];
|
|
5934
|
+
const artOnly = [];
|
|
5935
|
+
const kept = new Map;
|
|
5936
|
+
for (const n of transparent) {
|
|
5937
|
+
const reason = reasons.get(n);
|
|
5938
|
+
if (reason === "no-text")
|
|
5939
|
+
artOnly.push(n);
|
|
5940
|
+
else if (flattenPages.includes(n))
|
|
5941
|
+
kept.set(n, "listed");
|
|
5942
|
+
else if (reason)
|
|
5943
|
+
kept.set(n, reason);
|
|
5944
|
+
else if (gradientPages.includes(n))
|
|
5945
|
+
kept.set(n, "gradient");
|
|
5946
|
+
else
|
|
5947
|
+
split.push(n);
|
|
5948
|
+
}
|
|
5949
|
+
return { split, artOnly, kept };
|
|
5950
|
+
}
|
|
5951
|
+
async function flattenTransparentPages(pdfPath, pageNumbers, stagingDir, dpi = 300) {
|
|
5952
|
+
const pages = [...new Set(pageNumbers)].sort((a, b) => a - b);
|
|
5953
|
+
if (pages.length === 0)
|
|
5954
|
+
return;
|
|
5955
|
+
const ghostscript = await resolveGhostscript();
|
|
5956
|
+
if (!ghostscript) {
|
|
5957
|
+
throw new Error("Ghostscript executable not found. Install Ghostscript or set GHOSTSCRIPT_PATH to its command-line executable.");
|
|
5958
|
+
}
|
|
5959
|
+
const art = join3(stagingDir, "flatten-art.pdf");
|
|
5960
|
+
const text = join3(stagingDir, "flatten-text.pdf");
|
|
5961
|
+
const pageList = `-sPageList=${pages.join(",")}`;
|
|
5962
|
+
const gs = (...args) => run(ghostscript, [
|
|
5963
|
+
"-q",
|
|
5964
|
+
"-dBATCH",
|
|
5965
|
+
"-dNOPAUSE",
|
|
5966
|
+
"-dSAFER",
|
|
5967
|
+
"-dPreserveAnnots=false",
|
|
5968
|
+
"-dNO_PDFMARK_OUTLINES",
|
|
5969
|
+
...args
|
|
5970
|
+
]);
|
|
5971
|
+
try {
|
|
5972
|
+
await gs(pageList, "-sDEVICE=pdfimage24", "-dFILTERTEXT", `-r${dpi}`, `-sOutputFile=${art}`, pdfPath);
|
|
5973
|
+
await gs(pageList, "-sDEVICE=pdfwrite", "-dNOTRANSPARENCY", "-dFILTERIMAGE", "-dFILTERVECTOR", "-dCompatibilityLevel=1.3", `-sOutputFile=${text}`, pdfPath);
|
|
5974
|
+
const { PDFDocument, PDFName } = await import("pdf-lib");
|
|
5975
|
+
const doc = await PDFDocument.load(await readFile9(pdfPath), { updateMetadata: false });
|
|
5976
|
+
const artDoc = await PDFDocument.load(await readFile9(art));
|
|
5977
|
+
const textDoc = await PDFDocument.load(await readFile9(text));
|
|
5978
|
+
if (artDoc.getPageCount() !== pages.length || textDoc.getPageCount() !== pages.length) {
|
|
5979
|
+
throw new Error(`Ghostscript returned ${artDoc.getPageCount()} artwork and ${textDoc.getPageCount()} text pages for ${pages.length} transparent pages.`);
|
|
5980
|
+
}
|
|
5981
|
+
const artPages = await doc.embedPages(artDoc.getPages());
|
|
5982
|
+
const withText = textDoc.getPages().filter((p) => p.node.Contents());
|
|
5983
|
+
const embeddedText = await doc.embedPages(withText);
|
|
5984
|
+
const textPages = textDoc.getPages().map((p) => embeddedText[withText.indexOf(p)]);
|
|
5985
|
+
pages.forEach((pageNumber, i) => {
|
|
5986
|
+
const page = doc.getPage(pageNumber - 1);
|
|
5987
|
+
const { x, y, width, height } = page.getMediaBox();
|
|
5988
|
+
page.node.set(PDFName.of("Contents"), doc.context.obj([]));
|
|
5989
|
+
page.node.set(PDFName.of("Resources"), doc.context.obj({}));
|
|
5990
|
+
page.node.delete(PDFName.of("Group"));
|
|
5991
|
+
page.drawPage(artPages[i], { x, y, width, height });
|
|
5992
|
+
const textPage = textPages[i];
|
|
5993
|
+
if (textPage)
|
|
5994
|
+
page.drawPage(textPage, { x, y, width, height });
|
|
5995
|
+
});
|
|
5996
|
+
await writeFile3(pdfPath, await doc.save());
|
|
5997
|
+
} finally {
|
|
5998
|
+
await Promise.all([art, text].map((f) => unlink2(f).catch(() => {})));
|
|
5999
|
+
}
|
|
6000
|
+
}
|
|
5879
6001
|
function makePdfxDefPs(params) {
|
|
5880
6002
|
const pdfxVersion = params.pdfx === "x3" ? "PDF/X-3:2002" : "PDF/X-1:2001";
|
|
5881
6003
|
const pdfxConformance = params.pdfx === "x1a" ? "PDF/X-1a:2001" : null;
|
|
@@ -5967,6 +6089,10 @@ async function convertToPdfxCmyk(inputPdf, outPdf, config) {
|
|
|
5967
6089
|
"-dDownsampleColorImages=false",
|
|
5968
6090
|
"-dDownsampleGrayImages=false",
|
|
5969
6091
|
"-dDownsampleMonoImages=false",
|
|
6092
|
+
"-dAutoFilterColorImages=false",
|
|
6093
|
+
"-dColorImageFilter=/FlateEncode",
|
|
6094
|
+
"-dAutoFilterGrayImages=false",
|
|
6095
|
+
"-dGrayImageFilter=/FlateEncode",
|
|
5970
6096
|
...config.rasterDpi ? [`-r${config.rasterDpi}`] : [],
|
|
5971
6097
|
"-sProcessColorModel=DeviceCMYK",
|
|
5972
6098
|
"-sColorConversionStrategy=CMYK",
|
|
@@ -6017,7 +6143,7 @@ import git from "isomorphic-git";
|
|
|
6017
6143
|
// package.json
|
|
6018
6144
|
var package_default = {
|
|
6019
6145
|
name: "gutterpress",
|
|
6020
|
-
version: "0.11.20-alpha.
|
|
6146
|
+
version: "0.11.20-alpha.3",
|
|
6021
6147
|
description: "Markdown-to-PDF converter for professional print layout using a native Chromium print engine and Ghostscript.",
|
|
6022
6148
|
author: "itlackey",
|
|
6023
6149
|
license: "MPL-2.0",
|
|
@@ -6272,7 +6398,10 @@ async function writeBuildFingerprint(input) {
|
|
|
6272
6398
|
resolvedFlavor: input.pdfx.resolvedFlavor,
|
|
6273
6399
|
iccPath: input.pdfx.iccPath,
|
|
6274
6400
|
stripAnnotations: input.pdfx.stripAnnotations,
|
|
6275
|
-
blackText: input.pdfx.blackText ?? null
|
|
6401
|
+
blackText: input.pdfx.blackText ?? null,
|
|
6402
|
+
transparency: input.pdfx.transparency ?? null,
|
|
6403
|
+
flattenPages: input.pdfx.flattenPages ?? null,
|
|
6404
|
+
rasterDpi: input.pdfx.rasterDpi ?? null
|
|
6276
6405
|
},
|
|
6277
6406
|
outputDir: input.recordedOutputDir ? path10.resolve(input.recordedOutputDir) : outputDir
|
|
6278
6407
|
},
|
|
@@ -6614,346 +6743,6 @@ function inspectionFailed(checkId, message, extra = {}) {
|
|
|
6614
6743
|
};
|
|
6615
6744
|
}
|
|
6616
6745
|
|
|
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
6746
|
// src/checks/pdf/qpdf-structure.ts
|
|
6958
6747
|
var check2 = {
|
|
6959
6748
|
id: "pdf.structure.qpdf",
|
|
@@ -7228,9 +7017,9 @@ var check5 = {
|
|
|
7228
7017
|
registerCheck(check5);
|
|
7229
7018
|
|
|
7230
7019
|
// src/lib/pdf-parse.ts
|
|
7231
|
-
import { readFile as
|
|
7020
|
+
import { readFile as readFile13 } from "node:fs/promises";
|
|
7232
7021
|
async function readPdfBytes(pdfPath) {
|
|
7233
|
-
return
|
|
7022
|
+
return readFile13(pdfPath, "latin1");
|
|
7234
7023
|
}
|
|
7235
7024
|
function parseInkCov(out) {
|
|
7236
7025
|
const lines = out.split(/\r?\n/).filter((l) => l.includes("CMYK"));
|
|
@@ -7491,7 +7280,7 @@ var check9 = {
|
|
|
7491
7280
|
registerCheck(check9);
|
|
7492
7281
|
|
|
7493
7282
|
// src/checks/pdf/black-text.ts
|
|
7494
|
-
import { readFile as
|
|
7283
|
+
import { readFile as readFile14 } from "node:fs/promises";
|
|
7495
7284
|
var check10 = {
|
|
7496
7285
|
id: "pdf.print.black-text",
|
|
7497
7286
|
name: "Black Text",
|
|
@@ -7504,7 +7293,7 @@ var check10 = {
|
|
|
7504
7293
|
return [];
|
|
7505
7294
|
try {
|
|
7506
7295
|
const { findRichBlackText, LARGE_TEXT_PT } = await import("./black-text-gray-7dz61456.js");
|
|
7507
|
-
const found = await findRichBlackText(await
|
|
7296
|
+
const found = await findRichBlackText(await readFile14(ctx.pdfPath));
|
|
7508
7297
|
if (found.runs === 0)
|
|
7509
7298
|
return [];
|
|
7510
7299
|
return [
|
|
@@ -7894,7 +7683,7 @@ registerCheck(check19);
|
|
|
7894
7683
|
|
|
7895
7684
|
// src/checks/source/htmlhint.ts
|
|
7896
7685
|
import { existsSync as existsSync9 } from "node:fs";
|
|
7897
|
-
import { readFile as
|
|
7686
|
+
import { readFile as readFile15 } from "node:fs/promises";
|
|
7898
7687
|
import htmlhint from "htmlhint";
|
|
7899
7688
|
var { HTMLHint } = htmlhint;
|
|
7900
7689
|
var CONFIG_NAMES2 = [".htmlhintrc"];
|
|
@@ -7914,8 +7703,8 @@ var check20 = {
|
|
|
7914
7703
|
const resolvedConfig = findConfigFile(ctx.inputDir, CONFIG_NAMES2, configPath);
|
|
7915
7704
|
if (!resolvedConfig && !configPath)
|
|
7916
7705
|
return [];
|
|
7917
|
-
const ruleset = resolvedConfig ? JSON.parse(await
|
|
7918
|
-
const html = await
|
|
7706
|
+
const ruleset = resolvedConfig ? JSON.parse(await readFile15(resolvedConfig, "utf8")) : HTMLHint.defaultRuleset;
|
|
7707
|
+
const html = await readFile15(ctx.htmlPath, "utf8");
|
|
7919
7708
|
const messages = HTMLHint.verify(html, ruleset);
|
|
7920
7709
|
return messages.map((m) => ({
|
|
7921
7710
|
checkId: check20.id,
|
|
@@ -7930,7 +7719,7 @@ var check20 = {
|
|
|
7930
7719
|
registerCheck(check20);
|
|
7931
7720
|
|
|
7932
7721
|
// src/checks/source/stylelint.ts
|
|
7933
|
-
import { readFile as
|
|
7722
|
+
import { readFile as readFile16 } from "node:fs/promises";
|
|
7934
7723
|
|
|
7935
7724
|
// src/lib/printsafe.ts
|
|
7936
7725
|
import postcss2 from "postcss";
|
|
@@ -8272,7 +8061,7 @@ function checkCssRaw(css, from) {
|
|
|
8272
8061
|
warnings.push({
|
|
8273
8062
|
rule: ruleRiskyProps,
|
|
8274
8063
|
severity: "warning",
|
|
8275
|
-
message: `"${decl.prop}: ${decl.value}"
|
|
8064
|
+
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
8065
|
...nodeLoc(decl)
|
|
8277
8066
|
});
|
|
8278
8067
|
} else if (isUnpairedFitContentWidth(decl)) {
|
|
@@ -8337,7 +8126,7 @@ var check21 = {
|
|
|
8337
8126
|
for (const file of files) {
|
|
8338
8127
|
let css;
|
|
8339
8128
|
try {
|
|
8340
|
-
css = await
|
|
8129
|
+
css = await readFile16(file, "utf8");
|
|
8341
8130
|
} catch (err) {
|
|
8342
8131
|
results.push({
|
|
8343
8132
|
checkId: check21.id,
|
|
@@ -8364,12 +8153,12 @@ var check21 = {
|
|
|
8364
8153
|
registerCheck(check21);
|
|
8365
8154
|
|
|
8366
8155
|
// src/checks/source/css-ownership.ts
|
|
8367
|
-
import { readFile as
|
|
8156
|
+
import { readFile as readFile17 } from "node:fs/promises";
|
|
8368
8157
|
import postcss3 from "postcss";
|
|
8369
8158
|
import { parse as parseYaml3 } from "yaml";
|
|
8370
8159
|
var CONFIG_NAMES3 = [".gutterpress/css-contract.yaml", ".gutterpress/css-contract.yml"];
|
|
8371
8160
|
async function loadContract(configPath) {
|
|
8372
|
-
const raw = await
|
|
8161
|
+
const raw = await readFile17(configPath, "utf8");
|
|
8373
8162
|
const parsed = parseYaml3(raw);
|
|
8374
8163
|
if (parsed && typeof parsed === "object")
|
|
8375
8164
|
return parsed;
|
|
@@ -8520,7 +8309,7 @@ var check22 = {
|
|
|
8520
8309
|
continue;
|
|
8521
8310
|
let css;
|
|
8522
8311
|
try {
|
|
8523
|
-
css = await
|
|
8312
|
+
css = await readFile17(absFile, "utf8");
|
|
8524
8313
|
} catch {
|
|
8525
8314
|
continue;
|
|
8526
8315
|
}
|
|
@@ -8566,7 +8355,7 @@ import { existsSync as existsSync10 } from "node:fs";
|
|
|
8566
8355
|
import { dirname as dirname3, resolve as resolve6 } from "node:path";
|
|
8567
8356
|
|
|
8568
8357
|
// src/checks/source/local-ref-parser.ts
|
|
8569
|
-
import { readFile as
|
|
8358
|
+
import { readFile as readFile18 } from "node:fs/promises";
|
|
8570
8359
|
function newlineOffsets(content) {
|
|
8571
8360
|
const offsets = [];
|
|
8572
8361
|
for (let i = 0;i < content.length; i++)
|
|
@@ -8635,7 +8424,7 @@ async function* renderedLocalRefs(ctx, checkId, results) {
|
|
|
8635
8424
|
for (const file of files) {
|
|
8636
8425
|
let refs;
|
|
8637
8426
|
try {
|
|
8638
|
-
refs = collectRenderedLocalRefs(await
|
|
8427
|
+
refs = collectRenderedLocalRefs(await readFile18(file, "utf8"));
|
|
8639
8428
|
} catch {
|
|
8640
8429
|
results.push(inspectionFailed(checkId, `Could not read source file: ${file}`, { file }));
|
|
8641
8430
|
continue;
|
|
@@ -8986,7 +8775,7 @@ var check24 = {
|
|
|
8986
8775
|
registerCheck(check24);
|
|
8987
8776
|
|
|
8988
8777
|
// src/checks/source/accessibility-alt-text.ts
|
|
8989
|
-
import { readFile as
|
|
8778
|
+
import { readFile as readFile19 } from "node:fs/promises";
|
|
8990
8779
|
var check25 = {
|
|
8991
8780
|
id: "source.accessibility.alt-text",
|
|
8992
8781
|
name: "Image Alt Text",
|
|
@@ -9000,7 +8789,7 @@ var check25 = {
|
|
|
9000
8789
|
const results = [];
|
|
9001
8790
|
for (const file of files) {
|
|
9002
8791
|
try {
|
|
9003
|
-
const content = await
|
|
8792
|
+
const content = await readFile19(file, "utf8");
|
|
9004
8793
|
const lines = content.split(`
|
|
9005
8794
|
`);
|
|
9006
8795
|
let inFence = false;
|
|
@@ -9044,7 +8833,7 @@ function extractImageAlts(line) {
|
|
|
9044
8833
|
registerCheck(check25);
|
|
9045
8834
|
|
|
9046
8835
|
// src/checks/source/accessibility-heading-order.ts
|
|
9047
|
-
import { readFile as
|
|
8836
|
+
import { readFile as readFile20 } from "node:fs/promises";
|
|
9048
8837
|
var check26 = {
|
|
9049
8838
|
id: "source.accessibility.heading-order",
|
|
9050
8839
|
name: "Heading Order",
|
|
@@ -9058,7 +8847,7 @@ var check26 = {
|
|
|
9058
8847
|
const results = [];
|
|
9059
8848
|
for (const file of files) {
|
|
9060
8849
|
try {
|
|
9061
|
-
const content = await
|
|
8850
|
+
const content = await readFile20(file, "utf8");
|
|
9062
8851
|
const lines = content.split(`
|
|
9063
8852
|
`);
|
|
9064
8853
|
let inFence = false;
|
|
@@ -9100,7 +8889,7 @@ var check26 = {
|
|
|
9100
8889
|
registerCheck(check26);
|
|
9101
8890
|
|
|
9102
8891
|
// src/checks/source/layout-markers.ts
|
|
9103
|
-
import { readFile as
|
|
8892
|
+
import { readFile as readFile21 } from "node:fs/promises";
|
|
9104
8893
|
|
|
9105
8894
|
// src/lib/unknown-classes.ts
|
|
9106
8895
|
import postcss4 from "postcss";
|
|
@@ -9203,7 +8992,7 @@ async function collectKnownClasses(ctx, plugins) {
|
|
|
9203
8992
|
const sheets = (await collectStyleDependencies(ctx.inputDir, roots)).filter((f) => /\.css$/i.test(f));
|
|
9204
8993
|
for (const sheet of sheets) {
|
|
9205
8994
|
try {
|
|
9206
|
-
addCssClasses(await
|
|
8995
|
+
addCssClasses(await readFile21(sheet, "utf8"), names);
|
|
9207
8996
|
} catch {}
|
|
9208
8997
|
}
|
|
9209
8998
|
return names;
|
|
@@ -9227,7 +9016,7 @@ var check27 = {
|
|
|
9227
9016
|
const knownClasses = () => known ??= collectKnownClasses(ctx, plugins);
|
|
9228
9017
|
for (const file of files) {
|
|
9229
9018
|
try {
|
|
9230
|
-
const content = await
|
|
9019
|
+
const content = await readFile21(file, "utf8");
|
|
9231
9020
|
const env = {};
|
|
9232
9021
|
const tokens = md.parse(content, env);
|
|
9233
9022
|
md.renderer.render(tokens, md.options, env);
|
|
@@ -9267,7 +9056,7 @@ var check27 = {
|
|
|
9267
9056
|
registerCheck(check27);
|
|
9268
9057
|
|
|
9269
9058
|
// src/checks/source/merge-markers.ts
|
|
9270
|
-
import { readFile as
|
|
9059
|
+
import { readFile as readFile22 } from "node:fs/promises";
|
|
9271
9060
|
import path12 from "node:path";
|
|
9272
9061
|
|
|
9273
9062
|
// src/checks/asset/extensions.ts
|
|
@@ -9309,7 +9098,7 @@ var check28 = {
|
|
|
9309
9098
|
for (const file of textFiles) {
|
|
9310
9099
|
let content;
|
|
9311
9100
|
try {
|
|
9312
|
-
content = await
|
|
9101
|
+
content = await readFile22(file, "utf8");
|
|
9313
9102
|
} catch {
|
|
9314
9103
|
results.push(inspectionFailed(check28.id, `Could not read source file: ${file}`, { file }));
|
|
9315
9104
|
continue;
|
|
@@ -9369,7 +9158,7 @@ var check28 = {
|
|
|
9369
9158
|
registerCheck(check28);
|
|
9370
9159
|
|
|
9371
9160
|
// src/checks/source/characters.ts
|
|
9372
|
-
import { readFile as
|
|
9161
|
+
import { readFile as readFile23 } from "node:fs/promises";
|
|
9373
9162
|
|
|
9374
9163
|
// src/checks/source/character-table.ts
|
|
9375
9164
|
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 +9281,7 @@ var check29 = {
|
|
|
9492
9281
|
for (const file of (ctx.markdownFiles ?? []).slice().sort()) {
|
|
9493
9282
|
let content;
|
|
9494
9283
|
try {
|
|
9495
|
-
content = await
|
|
9284
|
+
content = await readFile23(file, "utf8");
|
|
9496
9285
|
} catch {
|
|
9497
9286
|
results.push(inspectionFailed(check29.id, `Could not read source file: ${file}`, { file }));
|
|
9498
9287
|
continue;
|
|
@@ -9532,16 +9321,16 @@ var check29 = {
|
|
|
9532
9321
|
registerCheck(check29);
|
|
9533
9322
|
|
|
9534
9323
|
// src/checks/asset/image-file-size.ts
|
|
9535
|
-
import { stat as
|
|
9324
|
+
import { stat as stat3 } from "node:fs/promises";
|
|
9536
9325
|
|
|
9537
9326
|
// src/lib/image-inspect.ts
|
|
9538
|
-
import { stat as
|
|
9327
|
+
import { stat as stat2, readFile as readFile24 } from "node:fs/promises";
|
|
9539
9328
|
var DEFAULT_DPI = 72;
|
|
9540
9329
|
var cache = new Map;
|
|
9541
9330
|
async function inspectImage(path13) {
|
|
9542
9331
|
let st;
|
|
9543
9332
|
try {
|
|
9544
|
-
st = await
|
|
9333
|
+
st = await stat2(path13);
|
|
9545
9334
|
} catch {
|
|
9546
9335
|
return null;
|
|
9547
9336
|
}
|
|
@@ -9550,7 +9339,7 @@ async function inspectImage(path13) {
|
|
|
9550
9339
|
return hit.info;
|
|
9551
9340
|
let info3 = null;
|
|
9552
9341
|
try {
|
|
9553
|
-
const buf = await
|
|
9342
|
+
const buf = await readFile24(path13);
|
|
9554
9343
|
info3 = parseImage(buf);
|
|
9555
9344
|
} catch {
|
|
9556
9345
|
info3 = null;
|
|
@@ -9772,7 +9561,7 @@ var check30 = {
|
|
|
9772
9561
|
const results = [];
|
|
9773
9562
|
for (const file of files) {
|
|
9774
9563
|
try {
|
|
9775
|
-
const info3 = await
|
|
9564
|
+
const info3 = await stat3(file);
|
|
9776
9565
|
if (info3.size > maxSize) {
|
|
9777
9566
|
const sizeMb = (info3.size / 1e6).toFixed(1);
|
|
9778
9567
|
const maxMb = (maxSize / 1e6).toFixed(1);
|
|
@@ -10110,7 +9899,7 @@ var check37 = {
|
|
|
10110
9899
|
registerCheck(check37);
|
|
10111
9900
|
|
|
10112
9901
|
// src/checks/heuristic/section-density.ts
|
|
10113
|
-
import { readFile as
|
|
9902
|
+
import { readFile as readFile25 } from "node:fs/promises";
|
|
10114
9903
|
var check38 = {
|
|
10115
9904
|
id: "heuristic.chunking.section-density",
|
|
10116
9905
|
name: "Section Density",
|
|
@@ -10127,7 +9916,7 @@ var check38 = {
|
|
|
10127
9916
|
const results = [];
|
|
10128
9917
|
for (const file of files) {
|
|
10129
9918
|
try {
|
|
10130
|
-
const content = await
|
|
9919
|
+
const content = await readFile25(file, "utf8");
|
|
10131
9920
|
const lines = content.split(`
|
|
10132
9921
|
`);
|
|
10133
9922
|
let currentSectionStart = 0;
|
|
@@ -11009,7 +10798,7 @@ class PdfOutput {
|
|
|
11009
10798
|
const rawPdf = pdfxMode ? path13.join(stage, "raw.pdf") : path13.resolve(pdfFile);
|
|
11010
10799
|
await fsp2.mkdir(path13.dirname(path13.resolve(pdfFile)), { recursive: true });
|
|
11011
10800
|
log.info("Rendering HTML to PDF via the Gutterpress engine (native Chromium pagination)");
|
|
11012
|
-
const { buildNativePdf } = await import("./engine-
|
|
10801
|
+
const { buildNativePdf } = await import("./engine-fdtv01a2.js");
|
|
11013
10802
|
const engineDiagnostics = await buildNativePdf(htmlFile, rawPdf, {
|
|
11014
10803
|
title: config.title,
|
|
11015
10804
|
author: config.authors.length > 0 ? config.authors.join(", ") : undefined,
|
|
@@ -11031,12 +10820,40 @@ class PdfOutput {
|
|
|
11031
10820
|
if (pdfxMode) {
|
|
11032
10821
|
const icc = opts.iccPath ?? config.pdfx.icc;
|
|
11033
10822
|
effectiveIccPath = await resolveIccProfile(icc, manifestDir, opts.iccPath);
|
|
11034
|
-
|
|
11035
|
-
|
|
10823
|
+
const rawBytes = await fsp2.readFile(rawPdf);
|
|
10824
|
+
const transparent = await transparentPages(rawBytes);
|
|
10825
|
+
const blankGradientPages = await findPostScriptShadingPages(rawBytes);
|
|
10826
|
+
const flattenedGradientPages = blankGradientPages.filter((n) => transparent.includes(n));
|
|
10827
|
+
const vectorGradientPages = blankGradientPages.filter((n) => !transparent.includes(n));
|
|
10828
|
+
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.";
|
|
10829
|
+
const pageList = (pages) => `Page${pages.length === 1 ? "" : "s"} ${pages.join(", ")}`;
|
|
10830
|
+
if (vectorGradientPages.length > 0) {
|
|
10831
|
+
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
10832
|
}
|
|
11037
|
-
|
|
11038
|
-
|
|
11039
|
-
|
|
10833
|
+
if (flattenedGradientPages.length > 0 && config.pdfx.transparency !== "preserve-text") {
|
|
10834
|
+
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}`);
|
|
10835
|
+
}
|
|
10836
|
+
const flattenPages = config.pdfx.flattenPages;
|
|
10837
|
+
if (transparent.length > 0 && config.pdfx.transparency === "preserve-text") {
|
|
10838
|
+
const { unsplittableTextReasons } = await import("./pdf-inspect-zdmy7qca.js");
|
|
10839
|
+
const reasons = await unsplittableTextReasons(rawBytes, transparent).catch((err) => {
|
|
10840
|
+
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.`);
|
|
10841
|
+
return null;
|
|
10842
|
+
});
|
|
10843
|
+
if (reasons) {
|
|
10844
|
+
const plan = planTransparentPages(transparent, reasons, flattenPages, blankGradientPages);
|
|
10845
|
+
await flattenTransparentPages(rawPdf, plan.split, stage, config.pdfx.rasterDpi);
|
|
10846
|
+
reportTransparentPlan(plan, pdfxMode, config.pdfx.rasterDpi ?? 300, pageList);
|
|
10847
|
+
}
|
|
10848
|
+
}
|
|
10849
|
+
const unused = flattenPages.filter((n) => !transparent.includes(n));
|
|
10850
|
+
if (flattenPages.length > 0 && config.pdfx.transparency !== "preserve-text") {
|
|
10851
|
+
log.warn("pdfx.flattenPages has no effect without pdfx.transparency: preserve-text.");
|
|
10852
|
+
} else if (unused.length > 0) {
|
|
10853
|
+
log.warn(`pdfx.flattenPages lists ${pageList(unused).toLowerCase()}, which ${unused.length === 1 ? "has" : "have"} no transparency (or do not exist): nothing to flatten there.`);
|
|
10854
|
+
}
|
|
10855
|
+
if (transparent.length > 0 && config.pdfx.transparency !== "preserve-text") {
|
|
10856
|
+
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
10857
|
}
|
|
11041
10858
|
const shouldStrip = opts.stripAnnotations ?? config.pdfx.stripAnnotations;
|
|
11042
10859
|
shouldStripAnnotations = shouldStrip;
|
|
@@ -11079,7 +10896,10 @@ class PdfOutput {
|
|
|
11079
10896
|
resolvedFlavor: config.pdfx.flavor,
|
|
11080
10897
|
iccPath: effectiveIccPath,
|
|
11081
10898
|
stripAnnotations: shouldStripAnnotations,
|
|
11082
|
-
blackText: pdfxMode ? config.pdfx.blackText : null
|
|
10899
|
+
blackText: pdfxMode ? config.pdfx.blackText : null,
|
|
10900
|
+
transparency: pdfxMode ? config.pdfx.transparency : null,
|
|
10901
|
+
flattenPages: pdfxMode ? config.pdfx.flattenPages : null,
|
|
10902
|
+
rasterDpi: pdfxMode ? config.pdfx.rasterDpi ?? null : null
|
|
11083
10903
|
}
|
|
11084
10904
|
}, `Wrote: ${reportedPdf}`, { htmlPath: htmlFile, pdfPath: reportedPdf }, pdfName, engineDiagnostics);
|
|
11085
10905
|
} finally {
|
|
@@ -11116,11 +10936,40 @@ async function runBuild(opts) {
|
|
|
11116
10936
|
await fsp2.rm(ctx.workDir, { recursive: true, force: true });
|
|
11117
10937
|
}
|
|
11118
10938
|
}
|
|
10939
|
+
var FALLBACK_CAUSE = {
|
|
10940
|
+
listed: "listed in pdfx.flattenPages",
|
|
10941
|
+
"text-transparency": "text drawn with transparency or blending (opacity, mix-blend-mode, a soft mask, a translucent text-shadow); keep that text opaque",
|
|
10942
|
+
"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",
|
|
10943
|
+
"text-pattern-or-clip": 'text filled with a pattern or used as a clip (SVG fill="url(#…)", gradient text, background-clip: text)',
|
|
10944
|
+
gradient: "a repeating or conic gradient; use a linear or radial gradient, or a small tiled image"
|
|
10945
|
+
};
|
|
10946
|
+
function reportTransparentPlan({ split, artOnly, kept }, pdfxMode, dpi, pageList) {
|
|
10947
|
+
const one = (pages, singular, plural) => pages.length === 1 ? singular : plural;
|
|
10948
|
+
if (split.length > 0) {
|
|
10949
|
+
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.`);
|
|
10950
|
+
}
|
|
10951
|
+
if (artOnly.length > 0) {
|
|
10952
|
+
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).`);
|
|
10953
|
+
}
|
|
10954
|
+
if (kept.size > 0) {
|
|
10955
|
+
const pages = [...kept.keys()];
|
|
10956
|
+
const byCause = new Map;
|
|
10957
|
+
for (const [n, cause] of kept)
|
|
10958
|
+
byCause.set(cause, [...byCause.get(cause) ?? [], n]);
|
|
10959
|
+
const lines = [...byCause].map(([cause, ns]) => ` - ${one(ns, "page", "pages")} ${ns.join(", ")}: ${FALLBACK_CAUSE[cause]}`);
|
|
10960
|
+
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:
|
|
10961
|
+
` + lines.join(`
|
|
10962
|
+
`));
|
|
10963
|
+
}
|
|
10964
|
+
if (split.length === 0 && [...kept.values()].some((cause) => cause !== "listed")) {
|
|
10965
|
+
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).");
|
|
10966
|
+
}
|
|
10967
|
+
}
|
|
11119
10968
|
// src/preview/lifecycle.ts
|
|
11120
10969
|
import path16 from "path";
|
|
11121
10970
|
import { tmpdir } from "os";
|
|
11122
10971
|
import { randomBytes as randomBytes2 } from "crypto";
|
|
11123
|
-
import { readdir as readdir5, readFile as
|
|
10972
|
+
import { readdir as readdir5, readFile as readFile26, writeFile as writeFile6 } from "node:fs/promises";
|
|
11124
10973
|
|
|
11125
10974
|
// src/utils/file-utils.ts
|
|
11126
10975
|
import { promises as fs3 } from "fs";
|
|
@@ -11681,7 +11530,7 @@ async function cleanupOrphanTempDirs() {
|
|
|
11681
11530
|
const dir = path16.join(TEMP_DIR_BASE, entry);
|
|
11682
11531
|
const pidFile = path16.join(dir, PID_FILE_NAME);
|
|
11683
11532
|
try {
|
|
11684
|
-
const raw = await
|
|
11533
|
+
const raw = await readFile26(pidFile, "utf8");
|
|
11685
11534
|
const pid = parseInt(raw.trim(), 10);
|
|
11686
11535
|
if (!isProcessAlive(pid)) {
|
|
11687
11536
|
debug(`Removing orphan temp dir ${dir} (pid ${pid} not alive)`);
|
|
@@ -11788,7 +11637,7 @@ function createServerState(inputPath, tempDir, config, options) {
|
|
|
11788
11637
|
import http from "node:http";
|
|
11789
11638
|
import net from "node:net";
|
|
11790
11639
|
import { createHash as createHash5, randomUUID as randomUUID3 } from "node:crypto";
|
|
11791
|
-
import { readFile as
|
|
11640
|
+
import { readFile as readFile27, stat as stat4 } from "node:fs/promises";
|
|
11792
11641
|
import path17 from "path";
|
|
11793
11642
|
import { WebSocket, WebSocketServer } from "ws";
|
|
11794
11643
|
|
|
@@ -11877,7 +11726,7 @@ async function findAvailablePort(startPort, host = "127.0.0.1") {
|
|
|
11877
11726
|
async function serveStatic(absPath, res, cacheControl = "no-store", extraHeaders = {}) {
|
|
11878
11727
|
let filePath = absPath;
|
|
11879
11728
|
try {
|
|
11880
|
-
const s = await
|
|
11729
|
+
const s = await stat4(filePath);
|
|
11881
11730
|
if (s.isDirectory())
|
|
11882
11731
|
filePath = path17.join(filePath, "index.html");
|
|
11883
11732
|
} catch {
|
|
@@ -11887,7 +11736,7 @@ async function serveStatic(absPath, res, cacheControl = "no-store", extraHeaders
|
|
|
11887
11736
|
}
|
|
11888
11737
|
let data;
|
|
11889
11738
|
try {
|
|
11890
|
-
data = await
|
|
11739
|
+
data = await readFile27(filePath);
|
|
11891
11740
|
} catch {
|
|
11892
11741
|
res.writeHead(404);
|
|
11893
11742
|
res.end("Not Found");
|
|
@@ -11916,7 +11765,7 @@ async function serveRevalidatedStatic(req, absPath, res, validators) {
|
|
|
11916
11765
|
}
|
|
11917
11766
|
let fileStat;
|
|
11918
11767
|
try {
|
|
11919
|
-
fileStat = await
|
|
11768
|
+
fileStat = await stat4(absPath, { bigint: true });
|
|
11920
11769
|
} catch {
|
|
11921
11770
|
await serveStatic(absPath, res);
|
|
11922
11771
|
return;
|
|
@@ -11936,7 +11785,7 @@ async function serveRevalidatedStatic(req, absPath, res, validators) {
|
|
|
11936
11785
|
let data;
|
|
11937
11786
|
if (!validator || validator.stamp !== stamp) {
|
|
11938
11787
|
try {
|
|
11939
|
-
data = await
|
|
11788
|
+
data = await readFile27(absPath);
|
|
11940
11789
|
} catch {
|
|
11941
11790
|
await serveStatic(absPath, res);
|
|
11942
11791
|
return;
|
|
@@ -11964,7 +11813,7 @@ async function isMissingReferencedImage(pathname, absPath, refs) {
|
|
|
11964
11813
|
if (!refs.has(imageRefKey(pathname)))
|
|
11965
11814
|
return false;
|
|
11966
11815
|
try {
|
|
11967
|
-
await
|
|
11816
|
+
await stat4(absPath);
|
|
11968
11817
|
return false;
|
|
11969
11818
|
} catch (err) {
|
|
11970
11819
|
return err?.code === "ENOENT";
|
|
@@ -12248,7 +12097,7 @@ async function startPreviewServer(options) {
|
|
|
12248
12097
|
import { platform, arch, release } from "node:os";
|
|
12249
12098
|
|
|
12250
12099
|
// src/lib/remote-auth/token-store.ts
|
|
12251
|
-
import { chmod, mkdir as mkdir7, readFile as
|
|
12100
|
+
import { chmod, mkdir as mkdir7, readFile as readFile28, rename as rename4, writeFile as writeFile7 } from "node:fs/promises";
|
|
12252
12101
|
import os3 from "node:os";
|
|
12253
12102
|
import path18 from "node:path";
|
|
12254
12103
|
function credentialHostKey(hostOrUrl) {
|
|
@@ -12292,7 +12141,7 @@ class FileTokenStore {
|
|
|
12292
12141
|
async read() {
|
|
12293
12142
|
let raw;
|
|
12294
12143
|
try {
|
|
12295
|
-
raw = await
|
|
12144
|
+
raw = await readFile28(this.filePath, "utf8");
|
|
12296
12145
|
} catch (e) {
|
|
12297
12146
|
if (e?.code === "ENOENT") {
|
|
12298
12147
|
return { version: 1, credentials: {} };
|
|
@@ -12492,13 +12341,13 @@ async function getSystemDiagnostics() {
|
|
|
12492
12341
|
};
|
|
12493
12342
|
}
|
|
12494
12343
|
// src/lib/project-scaffold.ts
|
|
12495
|
-
import { access, copyFile, cp as cp2, mkdir as mkdir9, readdir as readdir6, readFile as
|
|
12344
|
+
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
12345
|
import { constants as FS, existsSync as existsSync14 } from "node:fs";
|
|
12497
12346
|
import path20 from "node:path";
|
|
12498
12347
|
|
|
12499
12348
|
// src/lib/page-size.ts
|
|
12500
12349
|
import { existsSync as existsSync13 } from "node:fs";
|
|
12501
|
-
import { mkdir as mkdir8, readFile as
|
|
12350
|
+
import { mkdir as mkdir8, readFile as readFile29, writeFile as writeFile8 } from "node:fs/promises";
|
|
12502
12351
|
import path19 from "node:path";
|
|
12503
12352
|
import postcss5 from "postcss";
|
|
12504
12353
|
import { Scalar as Scalar2 } from "yaml";
|
|
@@ -12603,7 +12452,7 @@ var relDisplay2 = (projectDir, abs) => path19.relative(projectDir, abs).split(pa
|
|
|
12603
12452
|
async function findCssSize(projectDir, sheets) {
|
|
12604
12453
|
let found = null;
|
|
12605
12454
|
for (const file of sheets) {
|
|
12606
|
-
const size = readPageSizeFromCss(await
|
|
12455
|
+
const size = readPageSizeFromCss(await readFile29(file, "utf8"));
|
|
12607
12456
|
if (size)
|
|
12608
12457
|
found = { file, size };
|
|
12609
12458
|
}
|
|
@@ -12630,7 +12479,7 @@ async function setPageSetup(projectDir, choice) {
|
|
|
12630
12479
|
const found = await findCssSize(projectDir, sheets);
|
|
12631
12480
|
const newSheet = path19.join(projectDir, "styles", "book.css");
|
|
12632
12481
|
const target = found?.file ?? sheets[sheets.length - 1] ?? newSheet;
|
|
12633
|
-
const before = existsSync13(target) ? await
|
|
12482
|
+
const before = existsSync13(target) ? await readFile29(target, "utf8") : "";
|
|
12634
12483
|
let after;
|
|
12635
12484
|
try {
|
|
12636
12485
|
after = setPageSizeInCss(before, size);
|
|
@@ -12839,7 +12688,7 @@ async function adoptFolder(options) {
|
|
|
12839
12688
|
}
|
|
12840
12689
|
let st;
|
|
12841
12690
|
try {
|
|
12842
|
-
st = await
|
|
12691
|
+
st = await stat5(dir);
|
|
12843
12692
|
} catch {
|
|
12844
12693
|
throw new CreateProjectErrorImpl("scaffold-io", `Folder not found: ${dir}`);
|
|
12845
12694
|
}
|
|
@@ -12920,7 +12769,7 @@ styles:
|
|
|
12920
12769
|
async function firstSourceFile(manifestPath) {
|
|
12921
12770
|
let text;
|
|
12922
12771
|
try {
|
|
12923
|
-
text = await
|
|
12772
|
+
text = await readFile30(manifestPath, "utf8");
|
|
12924
12773
|
} catch {
|
|
12925
12774
|
return;
|
|
12926
12775
|
}
|
|
@@ -12932,14 +12781,14 @@ async function firstSourceFile(manifestPath) {
|
|
|
12932
12781
|
return m ? m[1].trim() : undefined;
|
|
12933
12782
|
}
|
|
12934
12783
|
async function fillTemplateFile(filePath, substitutions) {
|
|
12935
|
-
let text = await
|
|
12784
|
+
let text = await readFile30(filePath, "utf8");
|
|
12936
12785
|
for (const [token, value] of Object.entries(substitutions)) {
|
|
12937
12786
|
text = text.split(token).join(value);
|
|
12938
12787
|
}
|
|
12939
12788
|
await writeFile9(filePath, text, "utf8");
|
|
12940
12789
|
}
|
|
12941
12790
|
// src/lib/extension-scaffold.ts
|
|
12942
|
-
import { access as access2, mkdir as mkdir10, readFile as
|
|
12791
|
+
import { access as access2, mkdir as mkdir10, readFile as readFile31, writeFile as writeFile10 } from "node:fs/promises";
|
|
12943
12792
|
import { constants as FS2 } from "node:fs";
|
|
12944
12793
|
import path21 from "node:path";
|
|
12945
12794
|
var EXTENSION_KINDS = ["plugin", "theme"];
|
|
@@ -13056,7 +12905,7 @@ async function scaffoldExtension(options) {
|
|
|
13056
12905
|
const src = await getAssetPath(`extension-templates/${kind}/${assetName}`);
|
|
13057
12906
|
const dest = path21.join(extensionDir, relDest);
|
|
13058
12907
|
await mkdir10(path21.dirname(dest), { recursive: true });
|
|
13059
|
-
const text = await
|
|
12908
|
+
const text = await readFile31(src, "utf8");
|
|
13060
12909
|
const table = relDest.endsWith(".json") ? jsonSafe : plain;
|
|
13061
12910
|
await writeFile10(dest, substitute(text, table), "utf8");
|
|
13062
12911
|
written.push(relDest);
|
|
@@ -13082,7 +12931,7 @@ function substitute(text, table) {
|
|
|
13082
12931
|
return out;
|
|
13083
12932
|
}
|
|
13084
12933
|
// src/lib/project-templates.ts
|
|
13085
|
-
import { cp as cp3, mkdir as mkdir11, readFile as
|
|
12934
|
+
import { cp as cp3, mkdir as mkdir11, readFile as readFile32, readdir as readdir7, stat as stat6, writeFile as writeFile11 } from "node:fs/promises";
|
|
13086
12935
|
import { constants as FS3, existsSync as existsSync15 } from "node:fs";
|
|
13087
12936
|
import { access as access3 } from "node:fs/promises";
|
|
13088
12937
|
import path22 from "node:path";
|
|
@@ -13094,7 +12943,7 @@ var BUILT_IN_TEMPLATE_IDS = [
|
|
|
13094
12943
|
];
|
|
13095
12944
|
async function readTemplateChoices(manifestPath) {
|
|
13096
12945
|
try {
|
|
13097
|
-
const text = await
|
|
12946
|
+
const text = await readFile32(manifestPath, "utf8");
|
|
13098
12947
|
const doc = parseDocument2(text);
|
|
13099
12948
|
const out = {};
|
|
13100
12949
|
const preset = doc.get("preset");
|
|
@@ -13276,7 +13125,7 @@ async function saveProjectAsTemplate(options) {
|
|
|
13276
13125
|
async function retokeniseManifest(manifestPath) {
|
|
13277
13126
|
let text;
|
|
13278
13127
|
try {
|
|
13279
|
-
text = await
|
|
13128
|
+
text = await readFile32(manifestPath, "utf8");
|
|
13280
13129
|
} catch {
|
|
13281
13130
|
return;
|
|
13282
13131
|
}
|
|
@@ -13297,7 +13146,7 @@ async function listCustomTemplates(templatesRoot) {
|
|
|
13297
13146
|
const dir = path22.join(templatesRoot, entry.name);
|
|
13298
13147
|
let label = prettify(entry.name);
|
|
13299
13148
|
try {
|
|
13300
|
-
const meta = JSON.parse(await
|
|
13149
|
+
const meta = JSON.parse(await readFile32(path22.join(dir, TEMPLATE_META_FILE), "utf8"));
|
|
13301
13150
|
if (typeof meta.label === "string" && meta.label)
|
|
13302
13151
|
label = meta.label;
|
|
13303
13152
|
} catch {}
|
|
@@ -13315,7 +13164,7 @@ async function listCustomTemplates(templatesRoot) {
|
|
|
13315
13164
|
}
|
|
13316
13165
|
async function importTemplateFromFolder(options) {
|
|
13317
13166
|
const { sourceDir, templatesRoot } = options;
|
|
13318
|
-
const srcStat = await
|
|
13167
|
+
const srcStat = await stat6(sourceDir);
|
|
13319
13168
|
if (!srcStat.isDirectory()) {
|
|
13320
13169
|
throw new Error("The chosen path is not a folder.");
|
|
13321
13170
|
}
|
|
@@ -13323,7 +13172,7 @@ async function importTemplateFromFolder(options) {
|
|
|
13323
13172
|
return saveProjectAsTemplate({ projectDir: sourceDir, name, templatesRoot });
|
|
13324
13173
|
}
|
|
13325
13174
|
// src/lib/snippets.ts
|
|
13326
|
-
import { readdir as readdir8, readFile as
|
|
13175
|
+
import { readdir as readdir8, readFile as readFile33, writeFile as writeFile12, mkdir as mkdir12, rm as rm4 } from "node:fs/promises";
|
|
13327
13176
|
import path23 from "node:path";
|
|
13328
13177
|
var SNIPPETS_DIR = "snippets";
|
|
13329
13178
|
var LEVEL_RANK = { project: 0, extension: 1, core: 2 };
|
|
@@ -13364,7 +13213,7 @@ async function scanSnippetFiles(dir) {
|
|
|
13364
13213
|
continue;
|
|
13365
13214
|
let body = "";
|
|
13366
13215
|
try {
|
|
13367
|
-
body = await
|
|
13216
|
+
body = await readFile33(path23.join(dir, fileName), "utf8");
|
|
13368
13217
|
} catch {
|
|
13369
13218
|
continue;
|
|
13370
13219
|
}
|
|
@@ -13453,7 +13302,7 @@ async function collectLibrary(projectDir) {
|
|
|
13453
13302
|
listed.component = name;
|
|
13454
13303
|
continue;
|
|
13455
13304
|
}
|
|
13456
|
-
const body = await
|
|
13305
|
+
const body = await readFile33(path23.join(entry.dir, rel), "utf8").catch(() => null);
|
|
13457
13306
|
if (body === null)
|
|
13458
13307
|
continue;
|
|
13459
13308
|
snippets2.push({
|
|
@@ -13522,7 +13371,7 @@ async function listLocationVariants(projectDir) {
|
|
|
13522
13371
|
}
|
|
13523
13372
|
// src/lib/extension-import.ts
|
|
13524
13373
|
import { existsSync as existsSync16 } from "node:fs";
|
|
13525
|
-
import { cp as cp4, mkdir as mkdir13, mkdtemp as mkdtemp2, readFile as
|
|
13374
|
+
import { cp as cp4, mkdir as mkdir13, mkdtemp as mkdtemp2, readFile as readFile34, rm as rm5, writeFile as writeFile13 } from "node:fs/promises";
|
|
13526
13375
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
13527
13376
|
import path24 from "node:path";
|
|
13528
13377
|
import { unzipSync } from "fflate";
|
|
@@ -13595,7 +13444,7 @@ async function finalizeExtensionImport(projectDir, sourceDir, relPaths, fallback
|
|
|
13595
13444
|
if (!existsSync16(cssPath)) {
|
|
13596
13445
|
throw new Error("A theme must contain a theme.css file.");
|
|
13597
13446
|
}
|
|
13598
|
-
const css = await
|
|
13447
|
+
const css = await readFile34(cssPath, "utf8");
|
|
13599
13448
|
const { reject, warnings: printFindings } = classifyThemeCssFindings(checkCss(css, "theme.css"));
|
|
13600
13449
|
if (reject) {
|
|
13601
13450
|
throw new Error(`theme.css could not be parsed — ${reject.message}`);
|
|
@@ -13623,7 +13472,7 @@ async function finalizeExtensionImport(projectDir, sourceDir, relPaths, fallback
|
|
|
13623
13472
|
for (let i = 0;i < extraSheets.length; i++) {
|
|
13624
13473
|
const rel = extraSheets[i];
|
|
13625
13474
|
const sheetPath = extraSheetPaths[i];
|
|
13626
|
-
const sheetCss = await
|
|
13475
|
+
const sheetCss = await readFile34(sheetPath, "utf8");
|
|
13627
13476
|
const { reject: sheetReject, warnings: sheetFindings } = classifyThemeCssFindings(checkCss(sheetCss, rel));
|
|
13628
13477
|
if (sheetReject) {
|
|
13629
13478
|
throw new Error(`${rel} could not be parsed — ${sheetReject.message}`);
|
|
@@ -13656,7 +13505,7 @@ async function completeLandedManifest(dest, id, meta, metaExists) {
|
|
|
13656
13505
|
let pkg = {};
|
|
13657
13506
|
if (metaExists) {
|
|
13658
13507
|
try {
|
|
13659
|
-
const parsed = JSON.parse(await
|
|
13508
|
+
const parsed = JSON.parse(await readFile34(file, "utf8"));
|
|
13660
13509
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
13661
13510
|
pkg = parsed;
|
|
13662
13511
|
}
|
|
@@ -13758,11 +13607,11 @@ async function importExtensionFromCssText(projectDir, css, name) {
|
|
|
13758
13607
|
async function importExtensionFromFile(projectDir, filePath) {
|
|
13759
13608
|
const ext = path24.extname(filePath).toLowerCase();
|
|
13760
13609
|
if (ext === ".zip") {
|
|
13761
|
-
const buf = await
|
|
13610
|
+
const buf = await readFile34(filePath);
|
|
13762
13611
|
return importExtensionFromZip(projectDir, new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength));
|
|
13763
13612
|
}
|
|
13764
13613
|
if (ext === ".css") {
|
|
13765
|
-
const css = await
|
|
13614
|
+
const css = await readFile34(filePath, "utf8");
|
|
13766
13615
|
return importExtensionFromCssText(projectDir, css, prettify(path24.basename(filePath, ".css")));
|
|
13767
13616
|
}
|
|
13768
13617
|
throw new Error("Choose a .zip extension package or a .css stylesheet.");
|
|
@@ -16143,7 +15992,7 @@ async function scorchedEarth(options) {
|
|
|
16143
15992
|
}
|
|
16144
15993
|
}
|
|
16145
15994
|
// src/lib/publish/run-publish.ts
|
|
16146
|
-
import { readdir as readdir12, stat as
|
|
15995
|
+
import { readdir as readdir12, stat as stat11 } from "node:fs/promises";
|
|
16147
15996
|
import path33 from "node:path";
|
|
16148
15997
|
|
|
16149
15998
|
// src/lib/publish/command-runner.ts
|
|
@@ -16374,7 +16223,7 @@ var drivethrurpgProvider = {
|
|
|
16374
16223
|
};
|
|
16375
16224
|
|
|
16376
16225
|
// src/lib/publish/providers/gdrive.ts
|
|
16377
|
-
import { mkdtemp as mkdtemp3, readFile as
|
|
16226
|
+
import { mkdtemp as mkdtemp3, readFile as readFile35, readdir as readdir11, rm as rm9, stat as stat8, writeFile as writeFile16 } from "node:fs/promises";
|
|
16378
16227
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
16379
16228
|
import path30 from "node:path";
|
|
16380
16229
|
import { Zip, ZipDeflate } from "fflate";
|
|
@@ -16766,12 +16615,12 @@ async function collectZipEntries(root, dir, out, onWarn) {
|
|
|
16766
16615
|
await collectZipEntries(root, full, out, onWarn);
|
|
16767
16616
|
} else if (entry.isFile()) {
|
|
16768
16617
|
const rel = path30.relative(root, full).split(path30.sep).join("/");
|
|
16769
|
-
out[rel] = await
|
|
16618
|
+
out[rel] = await readFile35(full);
|
|
16770
16619
|
} else if (entry.isSymbolicLink()) {
|
|
16771
|
-
const resolved = await
|
|
16620
|
+
const resolved = await stat8(full).catch(() => null);
|
|
16772
16621
|
if (resolved?.isFile()) {
|
|
16773
16622
|
const rel = path30.relative(root, full).split(path30.sep).join("/");
|
|
16774
|
-
out[rel] = await
|
|
16623
|
+
out[rel] = await readFile35(full);
|
|
16775
16624
|
} else if (resolved?.isDirectory()) {
|
|
16776
16625
|
await collectZipEntries(root, full, out, onWarn);
|
|
16777
16626
|
} else {
|
|
@@ -16841,7 +16690,7 @@ var gdriveProvider = {
|
|
|
16841
16690
|
cleanup: async () => {}
|
|
16842
16691
|
};
|
|
16843
16692
|
try {
|
|
16844
|
-
const artifactStat = await
|
|
16693
|
+
const artifactStat = await stat8(source.filePath);
|
|
16845
16694
|
const about = await driveAbout(fetchImpl, accessToken);
|
|
16846
16695
|
if (about.quota.limitBytes != null && about.quota.freeBytes != null) {
|
|
16847
16696
|
if (artifactStat.size > about.quota.freeBytes) {
|
|
@@ -16886,7 +16735,7 @@ var gdriveProvider = {
|
|
|
16886
16735
|
};
|
|
16887
16736
|
|
|
16888
16737
|
// src/lib/publish/butler.ts
|
|
16889
|
-
import { chmod as chmod2, mkdir as mkdir19, stat as
|
|
16738
|
+
import { chmod as chmod2, mkdir as mkdir19, stat as stat9, writeFile as writeFile17 } from "node:fs/promises";
|
|
16890
16739
|
import path31 from "node:path";
|
|
16891
16740
|
import { unzipSync as unzipSync2 } from "fflate";
|
|
16892
16741
|
var BUTLER_DOWNLOAD_TIMEOUT_MS = 300000;
|
|
@@ -16907,7 +16756,7 @@ function butlerBinaryName(platform2 = process.platform) {
|
|
|
16907
16756
|
}
|
|
16908
16757
|
async function fileExists2(p) {
|
|
16909
16758
|
try {
|
|
16910
|
-
return (await
|
|
16759
|
+
return (await stat9(p)).isFile();
|
|
16911
16760
|
} catch {
|
|
16912
16761
|
return false;
|
|
16913
16762
|
}
|
|
@@ -17150,7 +16999,7 @@ var kdpProvider = {
|
|
|
17150
16999
|
};
|
|
17151
17000
|
|
|
17152
17001
|
// src/lib/publish/providers/local-folder.ts
|
|
17153
|
-
import { cp as cp7, mkdir as mkdir20, stat as
|
|
17002
|
+
import { cp as cp7, mkdir as mkdir20, stat as stat10 } from "node:fs/promises";
|
|
17154
17003
|
import path32 from "node:path";
|
|
17155
17004
|
var LOCAL_PUBLISH_DEFAULT_DIR = "dist";
|
|
17156
17005
|
var info8 = {
|
|
@@ -17177,7 +17026,7 @@ var localFolderProvider = {
|
|
|
17177
17026
|
async preflight(req) {
|
|
17178
17027
|
const dir = localPublishDir(req);
|
|
17179
17028
|
try {
|
|
17180
|
-
const s = await
|
|
17029
|
+
const s = await stat10(dir);
|
|
17181
17030
|
if (!s.isDirectory()) {
|
|
17182
17031
|
return [
|
|
17183
17032
|
{ severity: "error", id: "local/not-a-folder", message: `${dir} exists but is not a folder.` }
|
|
@@ -17472,7 +17321,7 @@ var PDF_HINT = "Build the PDF first (gutterpress build, or export it from the ap
|
|
|
17472
17321
|
var HTML_HINT = "Build the website export first (gutterpress build --format html).";
|
|
17473
17322
|
async function artifactIssues(artifact) {
|
|
17474
17323
|
try {
|
|
17475
|
-
const s = await
|
|
17324
|
+
const s = await stat11(artifact.path);
|
|
17476
17325
|
if (artifact.format === "pdf" && !s.isFile()) {
|
|
17477
17326
|
return [
|
|
17478
17327
|
{
|
|
@@ -17518,7 +17367,7 @@ async function artifactIssues(artifact) {
|
|
|
17518
17367
|
var BUILD_FINGERPRINT_FILENAME = "build-fingerprint.json";
|
|
17519
17368
|
async function htmlDirIssues(dir) {
|
|
17520
17369
|
const issues = [];
|
|
17521
|
-
const isThere = async (rel) =>
|
|
17370
|
+
const isThere = async (rel) => stat11(path33.join(dir, rel)).then(() => true, () => false);
|
|
17522
17371
|
if (!await isThere(BOOK_HTML)) {
|
|
17523
17372
|
issues.push({
|
|
17524
17373
|
severity: "error",
|
|
@@ -17637,7 +17486,7 @@ async function disconnectPublishCredential(key, deps, options = {}) {
|
|
|
17637
17486
|
}
|
|
17638
17487
|
}
|
|
17639
17488
|
// src/lib/publish/selections.ts
|
|
17640
|
-
import { chmod as chmod3, mkdir as mkdir21, readFile as
|
|
17489
|
+
import { chmod as chmod3, mkdir as mkdir21, readFile as readFile36, writeFile as writeFile18 } from "node:fs/promises";
|
|
17641
17490
|
import path34 from "node:path";
|
|
17642
17491
|
class PublishSelectionsStore {
|
|
17643
17492
|
filePath;
|
|
@@ -17647,7 +17496,7 @@ class PublishSelectionsStore {
|
|
|
17647
17496
|
}
|
|
17648
17497
|
async read() {
|
|
17649
17498
|
try {
|
|
17650
|
-
const raw = await
|
|
17499
|
+
const raw = await readFile36(this.filePath, "utf8");
|
|
17651
17500
|
const parsed = JSON.parse(raw);
|
|
17652
17501
|
if (parsed && typeof parsed === "object") {
|
|
17653
17502
|
return {
|