gutterpress 0.11.17-alpha.3 → 0.11.17-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 +2 -1
- package/dist/black-text-gray-7dz61456.js +15 -0
- package/dist/{build-394c1ee1.js → build-fam0tqg6.js} +4 -3
- package/dist/checks/pdf/black-text.d.ts +3 -0
- package/dist/checks/pdf/index.d.ts +1 -0
- package/dist/{cli-9nba5ve6.js → cli-2kc34kme.js} +235 -605
- package/dist/{cli-3p1e95zc.js → cli-8apk8571.js} +1 -1
- package/dist/cli-ht1bcqdd.js +493 -0
- package/dist/{cli-d57bsfpb.js → cli-pqcb2nnb.js} +1 -1
- package/dist/cli.js +12 -12
- package/dist/{doctor-c459qv5j.js → doctor-zre5k5fg.js} +2 -2
- package/dist/{ext-ha7gg8h9.js → ext-hfqcg6ax.js} +4 -3
- package/dist/{index-bscfmg5r.js → index-gp503ze9.js} +230 -600
- package/dist/index-ht1bcqdd.js +493 -0
- package/dist/index.js +2 -1
- package/dist/lib/black-text-gray.d.ts +17 -0
- package/dist/{new-kky3z7kv.js → new-bjdf7bhg.js} +4 -3
- package/dist/{preflight-t8v6szq6.js → preflight-gvw01661.js} +4 -3
- package/dist/{preview-cxab4y5x.js → preview-1cschq8s.js} +4 -3
- package/dist/{publish-s2mtenb5.js → publish-ddqrb8s9.js} +4 -3
- package/dist/{validate-xaajdw4x.js → validate-3hjkgxrz.js} +4 -3
- package/package.json +1 -1
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import {
|
|
2
|
+
blackTextToGray
|
|
3
|
+
} from "./index-ht1bcqdd.js";
|
|
1
4
|
import {
|
|
2
5
|
BuildError,
|
|
3
6
|
EXIT_CODES,
|
|
@@ -5671,7 +5674,7 @@ import git from "isomorphic-git";
|
|
|
5671
5674
|
// package.json
|
|
5672
5675
|
var package_default = {
|
|
5673
5676
|
name: "gutterpress",
|
|
5674
|
-
version: "0.11.17-alpha.
|
|
5677
|
+
version: "0.11.17-alpha.4",
|
|
5675
5678
|
description: "Markdown-to-PDF converter for professional print layout using a native Chromium print engine and Ghostscript.",
|
|
5676
5679
|
author: "itlackey",
|
|
5677
5680
|
license: "MPL-2.0",
|
|
@@ -5938,417 +5941,6 @@ async function writeBuildFingerprint(input) {
|
|
|
5938
5941
|
return outPath;
|
|
5939
5942
|
}
|
|
5940
5943
|
|
|
5941
|
-
// src/lib/black-text-gray.ts
|
|
5942
|
-
var MAX_CHANNEL = 0.12;
|
|
5943
|
-
var MAX_SPREAD = 0.04;
|
|
5944
|
-
function isNearBlack([r, g, b]) {
|
|
5945
|
-
const max = Math.max(r, g, b);
|
|
5946
|
-
return max <= MAX_CHANNEL && max - Math.min(r, g, b) <= MAX_SPREAD;
|
|
5947
|
-
}
|
|
5948
|
-
var WS = new Set([0, 9, 10, 12, 13, 32]);
|
|
5949
|
-
var DELIM = new Set("()<>[]{}/%".split("").map((c) => c.charCodeAt(0)));
|
|
5950
|
-
function* tokenize(s) {
|
|
5951
|
-
let i = 0;
|
|
5952
|
-
const n = s.length;
|
|
5953
|
-
while (i < n) {
|
|
5954
|
-
const c = s.charCodeAt(i);
|
|
5955
|
-
if (WS.has(c)) {
|
|
5956
|
-
i++;
|
|
5957
|
-
continue;
|
|
5958
|
-
}
|
|
5959
|
-
const start = i;
|
|
5960
|
-
if (c === 37) {
|
|
5961
|
-
while (i < n && s[i] !== `
|
|
5962
|
-
` && s[i] !== "\r")
|
|
5963
|
-
i++;
|
|
5964
|
-
continue;
|
|
5965
|
-
}
|
|
5966
|
-
if (c === 40) {
|
|
5967
|
-
let depth = 0;
|
|
5968
|
-
while (i < n) {
|
|
5969
|
-
const d = s[i++];
|
|
5970
|
-
if (d === "\\")
|
|
5971
|
-
i++;
|
|
5972
|
-
else if (d === "(")
|
|
5973
|
-
depth++;
|
|
5974
|
-
else if (d === ")" && --depth === 0)
|
|
5975
|
-
break;
|
|
5976
|
-
}
|
|
5977
|
-
yield { text: s.slice(start, i), start, end: i, op: false };
|
|
5978
|
-
continue;
|
|
5979
|
-
}
|
|
5980
|
-
if (c === 60 && s[i + 1] === "<") {
|
|
5981
|
-
i += 2;
|
|
5982
|
-
yield { text: "<<", start, end: i, op: false };
|
|
5983
|
-
continue;
|
|
5984
|
-
}
|
|
5985
|
-
if (c === 62 && s[i + 1] === ">") {
|
|
5986
|
-
i += 2;
|
|
5987
|
-
yield { text: ">>", start, end: i, op: false };
|
|
5988
|
-
continue;
|
|
5989
|
-
}
|
|
5990
|
-
if (c === 60) {
|
|
5991
|
-
while (i < n && s[i] !== ">")
|
|
5992
|
-
i++;
|
|
5993
|
-
i++;
|
|
5994
|
-
yield { text: s.slice(start, i), start, end: i, op: false };
|
|
5995
|
-
continue;
|
|
5996
|
-
}
|
|
5997
|
-
if (c === 91 || c === 93 || c === 62 || c === 123 || c === 125 || c === 41) {
|
|
5998
|
-
i++;
|
|
5999
|
-
yield { text: s[start], start, end: i, op: false };
|
|
6000
|
-
continue;
|
|
6001
|
-
}
|
|
6002
|
-
i++;
|
|
6003
|
-
while (i < n && !WS.has(s.charCodeAt(i)) && !DELIM.has(s.charCodeAt(i)))
|
|
6004
|
-
i++;
|
|
6005
|
-
const text = s.slice(start, i);
|
|
6006
|
-
const isOperand = c === 47 || /^[+-]?(\d+\.?\d*|\.\d+)$/.test(text);
|
|
6007
|
-
yield { text, start, end: i, op: !isOperand };
|
|
6008
|
-
if (text === "ID") {
|
|
6009
|
-
const m = /\sEI(?=\s|$)/g;
|
|
6010
|
-
m.lastIndex = i;
|
|
6011
|
-
const hit = m.exec(s);
|
|
6012
|
-
i = hit ? hit.index + hit[0].length : n;
|
|
6013
|
-
}
|
|
6014
|
-
}
|
|
6015
|
-
}
|
|
6016
|
-
var LARGE_TEXT_PT = 24;
|
|
6017
|
-
var SIZE_EPS = 0.05;
|
|
6018
|
-
var area = (m) => Math.sqrt(Math.abs(m[0] * m[3] - m[1] * m[2]));
|
|
6019
|
-
|
|
6020
|
-
class TextScale {
|
|
6021
|
-
ctm;
|
|
6022
|
-
font = 0;
|
|
6023
|
-
tm = 1;
|
|
6024
|
-
stack = [];
|
|
6025
|
-
constructor(ctm) {
|
|
6026
|
-
this.ctm = ctm;
|
|
6027
|
-
}
|
|
6028
|
-
get unit() {
|
|
6029
|
-
return this.ctm;
|
|
6030
|
-
}
|
|
6031
|
-
get size() {
|
|
6032
|
-
return this.font * this.tm * this.ctm;
|
|
6033
|
-
}
|
|
6034
|
-
op(op, nums) {
|
|
6035
|
-
switch (op) {
|
|
6036
|
-
case "q":
|
|
6037
|
-
this.stack.push([this.ctm, this.font]);
|
|
6038
|
-
return false;
|
|
6039
|
-
case "Q": {
|
|
6040
|
-
const p = this.stack.pop();
|
|
6041
|
-
if (p)
|
|
6042
|
-
[this.ctm, this.font] = p;
|
|
6043
|
-
return true;
|
|
6044
|
-
}
|
|
6045
|
-
case "cm":
|
|
6046
|
-
if (nums.length === 6)
|
|
6047
|
-
this.ctm *= area(nums);
|
|
6048
|
-
return true;
|
|
6049
|
-
case "BT":
|
|
6050
|
-
this.tm = 1;
|
|
6051
|
-
return true;
|
|
6052
|
-
case "Tm":
|
|
6053
|
-
if (nums.length === 6)
|
|
6054
|
-
this.tm = area(nums);
|
|
6055
|
-
return true;
|
|
6056
|
-
case "Tf":
|
|
6057
|
-
this.font = Math.abs(nums[nums.length - 1] ?? 0) || 0;
|
|
6058
|
-
return true;
|
|
6059
|
-
}
|
|
6060
|
-
return false;
|
|
6061
|
-
}
|
|
6062
|
-
}
|
|
6063
|
-
function rewriteBlackText(src, ctx = {}) {
|
|
6064
|
-
let fill = null;
|
|
6065
|
-
let stroke = null;
|
|
6066
|
-
const stack = [];
|
|
6067
|
-
const scale = new TextScale(ctx.baseScale ?? 1);
|
|
6068
|
-
let inText = false;
|
|
6069
|
-
let fillDirty = false;
|
|
6070
|
-
let strokeDirty = false;
|
|
6071
|
-
const spans = [];
|
|
6072
|
-
let lastOp = "";
|
|
6073
|
-
let rect = null;
|
|
6074
|
-
const edits = [];
|
|
6075
|
-
let operands = [];
|
|
6076
|
-
const rgbOf = () => {
|
|
6077
|
-
if (operands.length !== 3)
|
|
6078
|
-
return null;
|
|
6079
|
-
const v = operands.map((t) => Number(t.text));
|
|
6080
|
-
return v.some((x) => Number.isNaN(x)) ? null : { rgb: v, raw: operands.map((t) => t.text).join(" ") };
|
|
6081
|
-
};
|
|
6082
|
-
const isSmall = () => scale.size <= LARGE_TEXT_PT + SIZE_EPS;
|
|
6083
|
-
let fillIns = null;
|
|
6084
|
-
let strokeIns = null;
|
|
6085
|
-
const syncOne = (colour, dirty, ins, at, gray, op) => {
|
|
6086
|
-
if (!colour || !isNearBlack(colour.rgb))
|
|
6087
|
-
return [dirty, ins];
|
|
6088
|
-
const small = isSmall();
|
|
6089
|
-
if (small && !dirty) {
|
|
6090
|
-
const e = { start: at, end: at, text: ` ${gray}` };
|
|
6091
|
-
edits.push(e);
|
|
6092
|
-
return [true, e];
|
|
6093
|
-
}
|
|
6094
|
-
if (!small && dirty) {
|
|
6095
|
-
if (ins)
|
|
6096
|
-
ins.text = "";
|
|
6097
|
-
else
|
|
6098
|
-
edits.push({ start: at, end: at, text: ` ${colour.raw} ${op}` });
|
|
6099
|
-
return [false, null];
|
|
6100
|
-
}
|
|
6101
|
-
return [dirty, ins];
|
|
6102
|
-
};
|
|
6103
|
-
const sync = (at) => {
|
|
6104
|
-
[fillDirty, fillIns] = syncOne(fill, fillDirty, fillIns, at, "0 g", "rg");
|
|
6105
|
-
[strokeDirty, strokeIns] = syncOne(stroke, strokeDirty, strokeIns, at, "0 G", "RG");
|
|
6106
|
-
};
|
|
6107
|
-
const flush = (s) => {
|
|
6108
|
-
for (const r of s.rects) {
|
|
6109
|
-
if (r.thickness > 0.2 * s.maxSmall)
|
|
6110
|
-
continue;
|
|
6111
|
-
edits.push({ start: r.start, end: r.start, text: "q 0 g " }, { start: r.end, end: r.end, text: " Q" });
|
|
6112
|
-
}
|
|
6113
|
-
};
|
|
6114
|
-
for (const t of tokenize(src)) {
|
|
6115
|
-
if (!t.op) {
|
|
6116
|
-
operands.push(t);
|
|
6117
|
-
continue;
|
|
6118
|
-
}
|
|
6119
|
-
const op = t.text;
|
|
6120
|
-
const nums = operands.map((o) => Number(o.text));
|
|
6121
|
-
const sizeMayHaveChanged = scale.op(op, nums);
|
|
6122
|
-
switch (op) {
|
|
6123
|
-
case "q":
|
|
6124
|
-
stack.push([fill, stroke]);
|
|
6125
|
-
break;
|
|
6126
|
-
case "Q": {
|
|
6127
|
-
const p = stack.pop();
|
|
6128
|
-
if (p)
|
|
6129
|
-
[fill, stroke] = p;
|
|
6130
|
-
break;
|
|
6131
|
-
}
|
|
6132
|
-
case "BT":
|
|
6133
|
-
inText = true;
|
|
6134
|
-
fillDirty = strokeDirty = false;
|
|
6135
|
-
fillIns = strokeIns = null;
|
|
6136
|
-
sync(t.end);
|
|
6137
|
-
break;
|
|
6138
|
-
case "Tf":
|
|
6139
|
-
case "Tm":
|
|
6140
|
-
if (inText && sizeMayHaveChanged)
|
|
6141
|
-
sync(t.end);
|
|
6142
|
-
break;
|
|
6143
|
-
case "ET":
|
|
6144
|
-
if (inText) {
|
|
6145
|
-
let ins = "";
|
|
6146
|
-
if (fillDirty && fill)
|
|
6147
|
-
ins += `${fill.raw} rg `;
|
|
6148
|
-
if (strokeDirty && stroke)
|
|
6149
|
-
ins += `${stroke.raw} RG `;
|
|
6150
|
-
if (ins)
|
|
6151
|
-
edits.push({ start: t.start, end: t.start, text: ins });
|
|
6152
|
-
}
|
|
6153
|
-
inText = false;
|
|
6154
|
-
fillIns = strokeIns = null;
|
|
6155
|
-
break;
|
|
6156
|
-
case "rg":
|
|
6157
|
-
case "RG": {
|
|
6158
|
-
const c = rgbOf();
|
|
6159
|
-
const isFill = op === "rg";
|
|
6160
|
-
if (isFill)
|
|
6161
|
-
fill = c;
|
|
6162
|
-
else
|
|
6163
|
-
stroke = c;
|
|
6164
|
-
if (inText && c && isNearBlack(c.rgb) && isSmall()) {
|
|
6165
|
-
edits.push({ start: operands[0].start, end: t.end, text: isFill ? "0 g" : "0 G" });
|
|
6166
|
-
if (isFill)
|
|
6167
|
-
fillDirty = true;
|
|
6168
|
-
else
|
|
6169
|
-
strokeDirty = true;
|
|
6170
|
-
} else if (inText) {
|
|
6171
|
-
if (isFill)
|
|
6172
|
-
fillDirty = false;
|
|
6173
|
-
else
|
|
6174
|
-
strokeDirty = false;
|
|
6175
|
-
}
|
|
6176
|
-
break;
|
|
6177
|
-
}
|
|
6178
|
-
case "g":
|
|
6179
|
-
case "k":
|
|
6180
|
-
case "sc":
|
|
6181
|
-
case "scn":
|
|
6182
|
-
case "cs":
|
|
6183
|
-
fill = null;
|
|
6184
|
-
if (inText)
|
|
6185
|
-
fillDirty = false;
|
|
6186
|
-
break;
|
|
6187
|
-
case "G":
|
|
6188
|
-
case "K":
|
|
6189
|
-
case "SC":
|
|
6190
|
-
case "SCN":
|
|
6191
|
-
case "CS":
|
|
6192
|
-
stroke = null;
|
|
6193
|
-
if (inText)
|
|
6194
|
-
strokeDirty = false;
|
|
6195
|
-
break;
|
|
6196
|
-
case "Do": {
|
|
6197
|
-
const name = operands[operands.length - 1]?.text;
|
|
6198
|
-
if (name?.startsWith("/"))
|
|
6199
|
-
ctx.onDo?.(name.slice(1), scale.unit);
|
|
6200
|
-
break;
|
|
6201
|
-
}
|
|
6202
|
-
case "BDC":
|
|
6203
|
-
case "BMC":
|
|
6204
|
-
spans.push({ hasSmall: false, maxSmall: 0, rects: [] });
|
|
6205
|
-
break;
|
|
6206
|
-
case "EMC": {
|
|
6207
|
-
const s = spans.pop();
|
|
6208
|
-
if (!s)
|
|
6209
|
-
break;
|
|
6210
|
-
const parent = spans[spans.length - 1];
|
|
6211
|
-
if (s.hasSmall)
|
|
6212
|
-
flush(s);
|
|
6213
|
-
else
|
|
6214
|
-
parent?.rects.push(...s.rects);
|
|
6215
|
-
if (parent && s.hasSmall) {
|
|
6216
|
-
parent.hasSmall = true;
|
|
6217
|
-
parent.maxSmall = Math.max(parent.maxSmall, s.maxSmall);
|
|
6218
|
-
}
|
|
6219
|
-
break;
|
|
6220
|
-
}
|
|
6221
|
-
case "Tj":
|
|
6222
|
-
case "TJ":
|
|
6223
|
-
case "'":
|
|
6224
|
-
case '"': {
|
|
6225
|
-
fillIns = strokeIns = null;
|
|
6226
|
-
const span = spans[spans.length - 1];
|
|
6227
|
-
if (span && inText && isSmall()) {
|
|
6228
|
-
span.hasSmall = true;
|
|
6229
|
-
span.maxSmall = Math.max(span.maxSmall, scale.size);
|
|
6230
|
-
}
|
|
6231
|
-
break;
|
|
6232
|
-
}
|
|
6233
|
-
case "re":
|
|
6234
|
-
rect = !inText && fill && isNearBlack(fill.rgb) && operands.length === 4 && nums.every((x) => !Number.isNaN(x)) ? { start: operands[0].start, thickness: Math.min(Math.abs(nums[2]), Math.abs(nums[3])) * scale.unit } : null;
|
|
6235
|
-
break;
|
|
6236
|
-
case "f":
|
|
6237
|
-
case "F":
|
|
6238
|
-
case "f*":
|
|
6239
|
-
if (rect && lastOp === "re")
|
|
6240
|
-
spans[spans.length - 1]?.rects.push({ ...rect, end: t.end });
|
|
6241
|
-
break;
|
|
6242
|
-
}
|
|
6243
|
-
lastOp = op;
|
|
6244
|
-
operands = [];
|
|
6245
|
-
}
|
|
6246
|
-
return applyEdits(src, edits);
|
|
6247
|
-
}
|
|
6248
|
-
function applyEdits(s, edits) {
|
|
6249
|
-
if (!edits.length)
|
|
6250
|
-
return s;
|
|
6251
|
-
edits.sort((a, b) => a.start - b.start);
|
|
6252
|
-
let out = "";
|
|
6253
|
-
let pos = 0;
|
|
6254
|
-
for (const e of edits) {
|
|
6255
|
-
out += s.slice(pos, e.start) + e.text;
|
|
6256
|
-
pos = e.end;
|
|
6257
|
-
}
|
|
6258
|
-
return out + s.slice(pos);
|
|
6259
|
-
}
|
|
6260
|
-
async function visitContent(doc, visit) {
|
|
6261
|
-
const { PDFName, PDFRawStream, PDFArray, PDFRef, PDFDict, decodePDFRawStream } = await import("pdf-lib");
|
|
6262
|
-
const ctx = doc.context;
|
|
6263
|
-
const SKIP = ["Filter", "DecodeParms", "Length"].map((k) => PDFName.of(k));
|
|
6264
|
-
let changed = false;
|
|
6265
|
-
const decode = (s) => {
|
|
6266
|
-
try {
|
|
6267
|
-
return Buffer.from(decodePDFRawStream(s).decode()).toString("latin1");
|
|
6268
|
-
} catch {
|
|
6269
|
-
return null;
|
|
6270
|
-
}
|
|
6271
|
-
};
|
|
6272
|
-
const replace = (ref, old, text) => {
|
|
6273
|
-
const entries = {};
|
|
6274
|
-
for (const [k, v] of old.dict.entries())
|
|
6275
|
-
if (!SKIP.includes(k))
|
|
6276
|
-
entries[k.decodeText()] = v;
|
|
6277
|
-
ctx.assign(ref, ctx.flateStream(Buffer.from(text, "latin1"), entries));
|
|
6278
|
-
changed = true;
|
|
6279
|
-
};
|
|
6280
|
-
const formScale = new Map;
|
|
6281
|
-
const formMatrixScale = (form) => {
|
|
6282
|
-
const m = form.dict.lookupMaybe(PDFName.of("Matrix"), PDFArray);
|
|
6283
|
-
const nums = m?.asArray().map((n) => Number(n.toString()));
|
|
6284
|
-
return nums?.length === 6 && !nums.some(Number.isNaN) ? area(nums) : 1;
|
|
6285
|
-
};
|
|
6286
|
-
const pages = doc.getPages();
|
|
6287
|
-
for (let p = 0;p < pages.length; p++) {
|
|
6288
|
-
const page = pages[p];
|
|
6289
|
-
const contents = page.node.Contents();
|
|
6290
|
-
const refs = [];
|
|
6291
|
-
if (contents instanceof PDFArray) {
|
|
6292
|
-
for (let i = 0;i < contents.size(); i++) {
|
|
6293
|
-
const r = contents.get(i);
|
|
6294
|
-
if (r instanceof PDFRef)
|
|
6295
|
-
refs.push(r);
|
|
6296
|
-
}
|
|
6297
|
-
} else if (contents instanceof PDFRawStream) {
|
|
6298
|
-
const r = page.node.get(PDFName.of("Contents"));
|
|
6299
|
-
if (r instanceof PDFRef)
|
|
6300
|
-
refs.push(r);
|
|
6301
|
-
}
|
|
6302
|
-
const streams = refs.map((r) => ctx.lookup(r));
|
|
6303
|
-
if (!refs.length || !streams.every((s) => s instanceof PDFRawStream))
|
|
6304
|
-
continue;
|
|
6305
|
-
const parts = streams.map((s) => decode(s));
|
|
6306
|
-
if (parts.some((q) => q === null))
|
|
6307
|
-
continue;
|
|
6308
|
-
const joined = parts.join(`
|
|
6309
|
-
`);
|
|
6310
|
-
const xobjects = page.node.Resources()?.lookupMaybe(PDFName.of("XObject"), PDFDict);
|
|
6311
|
-
const next = visit(joined, {
|
|
6312
|
-
baseScale: 1,
|
|
6313
|
-
onDo: (name, scale) => {
|
|
6314
|
-
const ref = xobjects?.get(PDFName.of(name));
|
|
6315
|
-
const form = ref instanceof PDFRef ? ctx.lookup(ref) : undefined;
|
|
6316
|
-
if (!(ref instanceof PDFRef) || !(form instanceof PDFRawStream))
|
|
6317
|
-
return;
|
|
6318
|
-
if (form.dict.get(PDFName.of("Subtype")) !== PDFName.of("Form"))
|
|
6319
|
-
return;
|
|
6320
|
-
const at = scale * formMatrixScale(form);
|
|
6321
|
-
formScale.set(ref.tag, Math.min(formScale.get(ref.tag) ?? Infinity, at));
|
|
6322
|
-
}
|
|
6323
|
-
});
|
|
6324
|
-
if (next === joined)
|
|
6325
|
-
continue;
|
|
6326
|
-
replace(refs[0], streams[0], next);
|
|
6327
|
-
page.node.set(PDFName.of("Contents"), refs[0]);
|
|
6328
|
-
}
|
|
6329
|
-
for (const [ref, obj] of ctx.enumerateIndirectObjects()) {
|
|
6330
|
-
if (!(obj instanceof PDFRawStream))
|
|
6331
|
-
continue;
|
|
6332
|
-
if (obj.dict.get(PDFName.of("Subtype")) !== PDFName.of("Form"))
|
|
6333
|
-
continue;
|
|
6334
|
-
const text = decode(obj);
|
|
6335
|
-
if (text === null)
|
|
6336
|
-
continue;
|
|
6337
|
-
const next = visit(text, {
|
|
6338
|
-
baseScale: formScale.get(ref.tag) ?? 0
|
|
6339
|
-
});
|
|
6340
|
-
if (next !== text)
|
|
6341
|
-
replace(ref, obj, next);
|
|
6342
|
-
}
|
|
6343
|
-
return changed;
|
|
6344
|
-
}
|
|
6345
|
-
async function blackTextToGray(pdf) {
|
|
6346
|
-
const { PDFDocument } = await import("pdf-lib");
|
|
6347
|
-
const doc = await PDFDocument.load(pdf, { updateMetadata: false });
|
|
6348
|
-
const changed = await visitContent(doc, (src, info2) => rewriteBlackText(src, info2));
|
|
6349
|
-
return changed ? doc.save({ updateFieldAppearances: false }) : pdf;
|
|
6350
|
-
}
|
|
6351
|
-
|
|
6352
5944
|
// src/lib/validation-exec.ts
|
|
6353
5945
|
import { existsSync as existsSync12 } from "node:fs";
|
|
6354
5946
|
import { dirname as dirname4, join as join4, resolve as resolve8 } from "node:path";
|
|
@@ -7482,8 +7074,46 @@ var check8 = {
|
|
|
7482
7074
|
};
|
|
7483
7075
|
registerCheck(check8);
|
|
7484
7076
|
|
|
7485
|
-
// src/checks/pdf/
|
|
7077
|
+
// src/checks/pdf/black-text.ts
|
|
7078
|
+
import { readFile as readFile15 } from "node:fs/promises";
|
|
7486
7079
|
var check9 = {
|
|
7080
|
+
id: "pdf.print.black-text",
|
|
7081
|
+
name: "Black Text",
|
|
7082
|
+
description: "Warns when text at or below 24pt is painted in a dark four-colour mix (black, or a near-black colour such as a dark brown)",
|
|
7083
|
+
category: "pdf",
|
|
7084
|
+
phase: "post-build",
|
|
7085
|
+
enabledWhen: (config) => config.pdfx.blackText === "k-only",
|
|
7086
|
+
async run(ctx) {
|
|
7087
|
+
if (!ctx.pdfPath)
|
|
7088
|
+
return [];
|
|
7089
|
+
try {
|
|
7090
|
+
const { findRichBlackText, LARGE_TEXT_PT } = await import("./black-text-gray-7dz61456.js");
|
|
7091
|
+
const found = await findRichBlackText(await readFile15(ctx.pdfPath));
|
|
7092
|
+
if (found.runs === 0)
|
|
7093
|
+
return [];
|
|
7094
|
+
return [
|
|
7095
|
+
finding(check9.id, {
|
|
7096
|
+
severity: "warning",
|
|
7097
|
+
message: `Dark four-colour text at ${LARGE_TEXT_PT}pt or smaller on page(s) ${found.pages.join(", ")}.`,
|
|
7098
|
+
file: ctx.pdfPath,
|
|
7099
|
+
detail: "Small text printed with all four inks can look fuzzy if the plates are slightly out of register, which is why print vendors such as DriveThruRPG want small black text on the black plate alone. `pdfx.blackText: k-only` already does that for near-black text; this text is either a dark colour (for example a dark brown, which keeps its colour) or painted in a way the build cannot rewrite (an image or a pattern). To print it on the black plate, make the text black (#000). If the colour is intended, set `lint.rules: { pdf.print.black-text: off }` in manifest.yaml.",
|
|
7100
|
+
code: "rich-black-text",
|
|
7101
|
+
data: { runs: found.runs, pages: found.pages }
|
|
7102
|
+
})
|
|
7103
|
+
];
|
|
7104
|
+
} catch {
|
|
7105
|
+
return [
|
|
7106
|
+
inspectionFailed(check9.id, "Could not inspect the PDF's text colours.", {
|
|
7107
|
+
file: ctx.pdfPath
|
|
7108
|
+
})
|
|
7109
|
+
];
|
|
7110
|
+
}
|
|
7111
|
+
}
|
|
7112
|
+
};
|
|
7113
|
+
registerCheck(check9);
|
|
7114
|
+
|
|
7115
|
+
// src/checks/pdf/signature.ts
|
|
7116
|
+
var check10 = {
|
|
7487
7117
|
id: "pdf.print.signature",
|
|
7488
7118
|
name: "Signature",
|
|
7489
7119
|
description: "Fails when the interior's page count does not fit the print signature (a multiple of it ending on a blank page, or one short of a multiple)",
|
|
@@ -7495,7 +7125,7 @@ var check9 = {
|
|
|
7495
7125
|
return [];
|
|
7496
7126
|
const doc = await loadPdf(ctx.pdfPath);
|
|
7497
7127
|
if (!doc) {
|
|
7498
|
-
return [inspectionFailed(
|
|
7128
|
+
return [inspectionFailed(check10.id, "Could not parse the PDF's page count.", { file: ctx.pdfPath })];
|
|
7499
7129
|
}
|
|
7500
7130
|
const size = ctx.config.print.signature;
|
|
7501
7131
|
const pages = doc.numPages;
|
|
@@ -7504,7 +7134,7 @@ var check9 = {
|
|
|
7504
7134
|
const data = { pages, signature: size };
|
|
7505
7135
|
if (pages % size !== 0) {
|
|
7506
7136
|
return [
|
|
7507
|
-
finding(
|
|
7137
|
+
finding(check10.id, {
|
|
7508
7138
|
severity: "error",
|
|
7509
7139
|
message: `Page count ${pages} does not fit a signature of ${size}: it must be a multiple of ${size}, or one short of one.`,
|
|
7510
7140
|
file: ctx.pdfPath,
|
|
@@ -7520,10 +7150,10 @@ var check9 = {
|
|
|
7520
7150
|
if (!await pageHasMarks(doc, pages))
|
|
7521
7151
|
return [];
|
|
7522
7152
|
} catch {
|
|
7523
|
-
return [inspectionFailed(
|
|
7153
|
+
return [inspectionFailed(check10.id, "Could not read the last page.", { file: ctx.pdfPath })];
|
|
7524
7154
|
}
|
|
7525
7155
|
return [
|
|
7526
|
-
finding(
|
|
7156
|
+
finding(check10.id, {
|
|
7527
7157
|
severity: "error",
|
|
7528
7158
|
message: `The last page (${pages}) has content, but the printer needs it blank for its own information.`,
|
|
7529
7159
|
file: ctx.pdfPath,
|
|
@@ -7534,10 +7164,10 @@ var check9 = {
|
|
|
7534
7164
|
];
|
|
7535
7165
|
}
|
|
7536
7166
|
};
|
|
7537
|
-
registerCheck(
|
|
7167
|
+
registerCheck(check10);
|
|
7538
7168
|
|
|
7539
7169
|
// src/checks/pdf/bookmarks.ts
|
|
7540
|
-
var
|
|
7170
|
+
var check11 = {
|
|
7541
7171
|
id: "pdf.nav.bookmarks",
|
|
7542
7172
|
name: "Bookmarks",
|
|
7543
7173
|
description: "Checks for PDF outline (bookmarks) tree",
|
|
@@ -7551,14 +7181,14 @@ var check10 = {
|
|
|
7551
7181
|
const doc = await loadPdf(ctx.pdfPath);
|
|
7552
7182
|
if (!doc) {
|
|
7553
7183
|
return [
|
|
7554
|
-
inspectionFailed(
|
|
7184
|
+
inspectionFailed(check11.id, "Could not inspect PDF for bookmarks.", {
|
|
7555
7185
|
file: ctx.pdfPath
|
|
7556
7186
|
})
|
|
7557
7187
|
];
|
|
7558
7188
|
}
|
|
7559
7189
|
if (await getOutlineCount(doc) === 0) {
|
|
7560
7190
|
return [
|
|
7561
|
-
finding(
|
|
7191
|
+
finding(check11.id, {
|
|
7562
7192
|
severity: "warning",
|
|
7563
7193
|
message: "PDF does not contain bookmarks (outline tree).",
|
|
7564
7194
|
file: ctx.pdfPath
|
|
@@ -7568,10 +7198,10 @@ var check10 = {
|
|
|
7568
7198
|
return [];
|
|
7569
7199
|
}
|
|
7570
7200
|
};
|
|
7571
|
-
registerCheck(
|
|
7201
|
+
registerCheck(check11);
|
|
7572
7202
|
|
|
7573
7203
|
// src/checks/pdf/toc-links.ts
|
|
7574
|
-
var
|
|
7204
|
+
var check12 = {
|
|
7575
7205
|
id: "pdf.nav.toc-links",
|
|
7576
7206
|
name: "TOC Links",
|
|
7577
7207
|
description: "Detects link annotations on TOC pages",
|
|
@@ -7586,7 +7216,7 @@ var check11 = {
|
|
|
7586
7216
|
if (!doc) {
|
|
7587
7217
|
return [
|
|
7588
7218
|
{
|
|
7589
|
-
checkId:
|
|
7219
|
+
checkId: check12.id,
|
|
7590
7220
|
severity: "warning",
|
|
7591
7221
|
message: "Could not inspect PDF for TOC links.",
|
|
7592
7222
|
file: ctx.pdfPath
|
|
@@ -7597,7 +7227,7 @@ var check11 = {
|
|
|
7597
7227
|
if (!hasLinks) {
|
|
7598
7228
|
return [
|
|
7599
7229
|
{
|
|
7600
|
-
checkId:
|
|
7230
|
+
checkId: check12.id,
|
|
7601
7231
|
severity: "warning",
|
|
7602
7232
|
message: "No link annotations found in PDF (expected for TOC).",
|
|
7603
7233
|
file: ctx.pdfPath
|
|
@@ -7607,10 +7237,10 @@ var check11 = {
|
|
|
7607
7237
|
return [];
|
|
7608
7238
|
}
|
|
7609
7239
|
};
|
|
7610
|
-
registerCheck(
|
|
7240
|
+
registerCheck(check12);
|
|
7611
7241
|
|
|
7612
7242
|
// src/checks/pdf/cross-refs.ts
|
|
7613
|
-
var
|
|
7243
|
+
var check13 = {
|
|
7614
7244
|
id: "pdf.nav.cross-refs",
|
|
7615
7245
|
name: "Cross References",
|
|
7616
7246
|
description: "Counts and verifies internal link annotations",
|
|
@@ -7623,7 +7253,7 @@ var check12 = {
|
|
|
7623
7253
|
if (!doc) {
|
|
7624
7254
|
return [
|
|
7625
7255
|
{
|
|
7626
|
-
checkId:
|
|
7256
|
+
checkId: check13.id,
|
|
7627
7257
|
severity: "info",
|
|
7628
7258
|
message: "Could not inspect PDF for cross-references.",
|
|
7629
7259
|
file: ctx.pdfPath
|
|
@@ -7633,7 +7263,7 @@ var check12 = {
|
|
|
7633
7263
|
const linkCount = await countLinkAnnotations(doc);
|
|
7634
7264
|
return [
|
|
7635
7265
|
{
|
|
7636
|
-
checkId:
|
|
7266
|
+
checkId: check13.id,
|
|
7637
7267
|
severity: "info",
|
|
7638
7268
|
message: `PDF contains ${linkCount} internal link annotation${linkCount !== 1 ? "s" : ""}.`,
|
|
7639
7269
|
file: ctx.pdfPath
|
|
@@ -7641,10 +7271,10 @@ var check12 = {
|
|
|
7641
7271
|
];
|
|
7642
7272
|
}
|
|
7643
7273
|
};
|
|
7644
|
-
registerCheck(
|
|
7274
|
+
registerCheck(check13);
|
|
7645
7275
|
|
|
7646
7276
|
// src/checks/pdf/page-labels.ts
|
|
7647
|
-
var
|
|
7277
|
+
var check14 = {
|
|
7648
7278
|
id: "pdf.nav.page-labels",
|
|
7649
7279
|
name: "Page Labels",
|
|
7650
7280
|
description: "Verifies PDF page labels / folio numbering",
|
|
@@ -7659,7 +7289,7 @@ var check13 = {
|
|
|
7659
7289
|
const labels = await getPageLabels(doc);
|
|
7660
7290
|
return [
|
|
7661
7291
|
{
|
|
7662
|
-
checkId:
|
|
7292
|
+
checkId: check14.id,
|
|
7663
7293
|
severity: "info",
|
|
7664
7294
|
message: labels && labels.length > 0 ? "PDF contains page labels." : "PDF does not contain explicit page labels.",
|
|
7665
7295
|
file: ctx.pdfPath
|
|
@@ -7667,10 +7297,10 @@ var check13 = {
|
|
|
7667
7297
|
];
|
|
7668
7298
|
}
|
|
7669
7299
|
};
|
|
7670
|
-
registerCheck(
|
|
7300
|
+
registerCheck(check14);
|
|
7671
7301
|
|
|
7672
7302
|
// src/checks/pdf/image-resolution.ts
|
|
7673
|
-
var
|
|
7303
|
+
var check15 = {
|
|
7674
7304
|
id: "pdf.print.image-resolution",
|
|
7675
7305
|
name: "Image Resolution",
|
|
7676
7306
|
description: "Checks DPI of images embedded in the PDF",
|
|
@@ -7697,7 +7327,7 @@ var check14 = {
|
|
|
7697
7327
|
lowResPages.sort((a, b) => a - b);
|
|
7698
7328
|
return [
|
|
7699
7329
|
{
|
|
7700
|
-
checkId:
|
|
7330
|
+
checkId: check15.id,
|
|
7701
7331
|
severity: "warning",
|
|
7702
7332
|
message: `Low-resolution images (below ${minDpi} DPI) found on pages: ${lowResPages.join(", ")}`,
|
|
7703
7333
|
file: ctx.pdfPath
|
|
@@ -7707,10 +7337,10 @@ var check14 = {
|
|
|
7707
7337
|
return [];
|
|
7708
7338
|
}
|
|
7709
7339
|
};
|
|
7710
|
-
registerCheck(
|
|
7340
|
+
registerCheck(check15);
|
|
7711
7341
|
|
|
7712
7342
|
// src/checks/pdf/transparency.ts
|
|
7713
|
-
var
|
|
7343
|
+
var check16 = {
|
|
7714
7344
|
id: "pdf.print.transparency",
|
|
7715
7345
|
name: "Transparency",
|
|
7716
7346
|
description: "Checks for transparency markers (/Transparency, /SMask, /BM) in the PDF",
|
|
@@ -7732,7 +7362,7 @@ var check15 = {
|
|
|
7732
7362
|
if (found.length > 0) {
|
|
7733
7363
|
return [
|
|
7734
7364
|
{
|
|
7735
|
-
checkId:
|
|
7365
|
+
checkId: check16.id,
|
|
7736
7366
|
severity: "warning",
|
|
7737
7367
|
message: `Transparency detected in PDF: ${found.join(", ")}. This may cause issues with some printers.`,
|
|
7738
7368
|
file: ctx.pdfPath
|
|
@@ -7742,7 +7372,7 @@ var check15 = {
|
|
|
7742
7372
|
return [];
|
|
7743
7373
|
}
|
|
7744
7374
|
};
|
|
7745
|
-
registerCheck(
|
|
7375
|
+
registerCheck(check16);
|
|
7746
7376
|
|
|
7747
7377
|
// src/checks/pdf/bleed.ts
|
|
7748
7378
|
function findBox(bytes, box) {
|
|
@@ -7752,7 +7382,7 @@ function findBox(bytes, box) {
|
|
|
7752
7382
|
return null;
|
|
7753
7383
|
return [Number(m[1]), Number(m[2]), Number(m[3]), Number(m[4])];
|
|
7754
7384
|
}
|
|
7755
|
-
var
|
|
7385
|
+
var check17 = {
|
|
7756
7386
|
id: "pdf.print.bleed",
|
|
7757
7387
|
name: "Bleed Box",
|
|
7758
7388
|
description: "Compares MediaBox vs TrimBox/BleedBox to verify bleed area",
|
|
@@ -7766,7 +7396,7 @@ var check16 = {
|
|
|
7766
7396
|
const bytes = await readPdfBytes(ctx.pdfPath).catch(() => "");
|
|
7767
7397
|
if (!bytes) {
|
|
7768
7398
|
return [
|
|
7769
|
-
inspectionFailed(
|
|
7399
|
+
inspectionFailed(check17.id, "Could not inspect PDF for bleed boxes.", {
|
|
7770
7400
|
file: ctx.pdfPath
|
|
7771
7401
|
})
|
|
7772
7402
|
];
|
|
@@ -7776,14 +7406,14 @@ var check16 = {
|
|
|
7776
7406
|
const bleed = findBox(bytes, "BleedBox");
|
|
7777
7407
|
if (!media) {
|
|
7778
7408
|
return [
|
|
7779
|
-
inspectionFailed(
|
|
7409
|
+
inspectionFailed(check17.id, "Could not parse MediaBox from PDF.", {
|
|
7780
7410
|
file: ctx.pdfPath
|
|
7781
7411
|
})
|
|
7782
7412
|
];
|
|
7783
7413
|
}
|
|
7784
7414
|
if (!trim && !bleed) {
|
|
7785
7415
|
return [
|
|
7786
|
-
finding(
|
|
7416
|
+
finding(check17.id, {
|
|
7787
7417
|
severity: "warning",
|
|
7788
7418
|
message: "No TrimBox or BleedBox found. Bleed area cannot be verified.",
|
|
7789
7419
|
file: ctx.pdfPath
|
|
@@ -7796,7 +7426,7 @@ var check16 = {
|
|
|
7796
7426
|
const bleedSize = ctx.config.validate.pdf.bleedSize;
|
|
7797
7427
|
if (mediaW - trimW < bleedSize * 2 * 0.9) {
|
|
7798
7428
|
return [
|
|
7799
|
-
finding(
|
|
7429
|
+
finding(check17.id, {
|
|
7800
7430
|
severity: "warning",
|
|
7801
7431
|
message: `Bleed area appears insufficient. Expected at least ${bleedSize}pt on each side.`,
|
|
7802
7432
|
file: ctx.pdfPath
|
|
@@ -7807,10 +7437,10 @@ var check16 = {
|
|
|
7807
7437
|
return [];
|
|
7808
7438
|
}
|
|
7809
7439
|
};
|
|
7810
|
-
registerCheck(
|
|
7440
|
+
registerCheck(check17);
|
|
7811
7441
|
|
|
7812
7442
|
// src/checks/pdf/pdfx-metadata.ts
|
|
7813
|
-
var
|
|
7443
|
+
var check18 = {
|
|
7814
7444
|
id: "pdf.print.pdfx-metadata",
|
|
7815
7445
|
name: "PDF/X Metadata",
|
|
7816
7446
|
description: "Verifies PDF/X DOCINFO metadata via qpdf JSON",
|
|
@@ -7829,30 +7459,30 @@ var check17 = {
|
|
|
7829
7459
|
const objects = parseQpdfObjectsJson(stdout);
|
|
7830
7460
|
if (!objects) {
|
|
7831
7461
|
return [
|
|
7832
|
-
inspectionFailed(
|
|
7462
|
+
inspectionFailed(check18.id, "Unable to parse qpdf JSON output for PDF/X metadata checks.", { file: ctx.pdfPath })
|
|
7833
7463
|
];
|
|
7834
7464
|
}
|
|
7835
|
-
return getPdfxMetadataIssues(objects, ctx.config.pdfx.flavor).map((message) => finding(
|
|
7465
|
+
return getPdfxMetadataIssues(objects, ctx.config.pdfx.flavor).map((message) => finding(check18.id, {
|
|
7836
7466
|
severity: "error",
|
|
7837
7467
|
message,
|
|
7838
7468
|
file: ctx.pdfPath
|
|
7839
7469
|
}));
|
|
7840
7470
|
} catch {
|
|
7841
7471
|
return [
|
|
7842
|
-
inspectionFailed(
|
|
7472
|
+
inspectionFailed(check18.id, "Failed to inspect PDF objects with qpdf for PDF/X metadata.", { file: ctx.pdfPath })
|
|
7843
7473
|
];
|
|
7844
7474
|
}
|
|
7845
7475
|
}
|
|
7846
7476
|
};
|
|
7847
|
-
registerCheck(
|
|
7477
|
+
registerCheck(check18);
|
|
7848
7478
|
|
|
7849
7479
|
// src/checks/source/htmlhint.ts
|
|
7850
7480
|
import { existsSync as existsSync9 } from "node:fs";
|
|
7851
|
-
import { readFile as
|
|
7481
|
+
import { readFile as readFile16 } from "node:fs/promises";
|
|
7852
7482
|
import htmlhint from "htmlhint";
|
|
7853
7483
|
var { HTMLHint } = htmlhint;
|
|
7854
7484
|
var CONFIG_NAMES2 = [".htmlhintrc"];
|
|
7855
|
-
var
|
|
7485
|
+
var check19 = {
|
|
7856
7486
|
id: "source.htmlhint",
|
|
7857
7487
|
name: "HTMLHint",
|
|
7858
7488
|
description: "Runs htmlhint with project config to validate generated HTML",
|
|
@@ -7868,11 +7498,11 @@ var check18 = {
|
|
|
7868
7498
|
const resolvedConfig = findConfigFile(ctx.inputDir, CONFIG_NAMES2, configPath);
|
|
7869
7499
|
if (!resolvedConfig && !configPath)
|
|
7870
7500
|
return [];
|
|
7871
|
-
const ruleset = resolvedConfig ? JSON.parse(await
|
|
7872
|
-
const html = await
|
|
7501
|
+
const ruleset = resolvedConfig ? JSON.parse(await readFile16(resolvedConfig, "utf8")) : HTMLHint.defaultRuleset;
|
|
7502
|
+
const html = await readFile16(ctx.htmlPath, "utf8");
|
|
7873
7503
|
const messages = HTMLHint.verify(html, ruleset);
|
|
7874
7504
|
return messages.map((m) => ({
|
|
7875
|
-
checkId:
|
|
7505
|
+
checkId: check19.id,
|
|
7876
7506
|
severity: m.type === "error" ? "error" : "warning",
|
|
7877
7507
|
message: `${m.rule.id}: ${m.message}`,
|
|
7878
7508
|
file: ctx.htmlPath,
|
|
@@ -7881,10 +7511,10 @@ var check18 = {
|
|
|
7881
7511
|
}));
|
|
7882
7512
|
}
|
|
7883
7513
|
};
|
|
7884
|
-
registerCheck(
|
|
7514
|
+
registerCheck(check19);
|
|
7885
7515
|
|
|
7886
7516
|
// src/checks/source/stylelint.ts
|
|
7887
|
-
import { readFile as
|
|
7517
|
+
import { readFile as readFile17 } from "node:fs/promises";
|
|
7888
7518
|
|
|
7889
7519
|
// src/lib/printsafe.ts
|
|
7890
7520
|
import postcss2 from "postcss";
|
|
@@ -8201,7 +7831,7 @@ function checkCssRaw(css, from) {
|
|
|
8201
7831
|
}
|
|
8202
7832
|
|
|
8203
7833
|
// src/checks/source/stylelint.ts
|
|
8204
|
-
var
|
|
7834
|
+
var check20 = {
|
|
8205
7835
|
id: "source.stylelint",
|
|
8206
7836
|
name: "Print-safety CSS",
|
|
8207
7837
|
description: "Checks CSS for print-safety issues (remote URLs, rasterizing effects, and page-layer containment)",
|
|
@@ -8218,10 +7848,10 @@ var check19 = {
|
|
|
8218
7848
|
for (const file of files) {
|
|
8219
7849
|
let css;
|
|
8220
7850
|
try {
|
|
8221
|
-
css = await
|
|
7851
|
+
css = await readFile17(file, "utf8");
|
|
8222
7852
|
} catch (err) {
|
|
8223
7853
|
results.push({
|
|
8224
|
-
checkId:
|
|
7854
|
+
checkId: check20.id,
|
|
8225
7855
|
severity: "error",
|
|
8226
7856
|
message: `Cannot read stylesheet: ${err instanceof Error ? err.message : String(err)}`,
|
|
8227
7857
|
file
|
|
@@ -8230,7 +7860,7 @@ var check19 = {
|
|
|
8230
7860
|
}
|
|
8231
7861
|
for (const w of checkCss(css, file, { rules: ctx.config.lint.rules })) {
|
|
8232
7862
|
results.push({
|
|
8233
|
-
checkId:
|
|
7863
|
+
checkId: check20.id,
|
|
8234
7864
|
severity: w.severity,
|
|
8235
7865
|
message: `${w.rule}: ${w.message}`,
|
|
8236
7866
|
file,
|
|
@@ -8242,15 +7872,15 @@ var check19 = {
|
|
|
8242
7872
|
return results;
|
|
8243
7873
|
}
|
|
8244
7874
|
};
|
|
8245
|
-
registerCheck(
|
|
7875
|
+
registerCheck(check20);
|
|
8246
7876
|
|
|
8247
7877
|
// src/checks/source/css-ownership.ts
|
|
8248
|
-
import { readFile as
|
|
7878
|
+
import { readFile as readFile18 } from "node:fs/promises";
|
|
8249
7879
|
import postcss3 from "postcss";
|
|
8250
7880
|
import { parse as parseYaml3 } from "yaml";
|
|
8251
7881
|
var CONFIG_NAMES3 = [".gutterpress/css-contract.yaml", ".gutterpress/css-contract.yml"];
|
|
8252
7882
|
async function loadContract(configPath) {
|
|
8253
|
-
const raw = await
|
|
7883
|
+
const raw = await readFile18(configPath, "utf8");
|
|
8254
7884
|
const parsed = parseYaml3(raw);
|
|
8255
7885
|
if (parsed && typeof parsed === "object")
|
|
8256
7886
|
return parsed;
|
|
@@ -8363,7 +7993,7 @@ function checkOwnership(root, file, maps) {
|
|
|
8363
7993
|
});
|
|
8364
7994
|
return out;
|
|
8365
7995
|
}
|
|
8366
|
-
var
|
|
7996
|
+
var check21 = {
|
|
8367
7997
|
id: "source.css-ownership",
|
|
8368
7998
|
name: "CSS ownership contract",
|
|
8369
7999
|
description: "Checks an optional per-project CSS ownership contract (.gutterpress/css-contract.yaml): which file may declare which properties/at-rules, and which selectors must never appear unscoped.",
|
|
@@ -8386,7 +8016,7 @@ var check20 = {
|
|
|
8386
8016
|
} catch (err) {
|
|
8387
8017
|
return [
|
|
8388
8018
|
{
|
|
8389
|
-
checkId:
|
|
8019
|
+
checkId: check21.id,
|
|
8390
8020
|
severity: "error",
|
|
8391
8021
|
message: `Failed to parse CSS ownership contract "${configPath}": ${err instanceof Error ? err.message : String(err)}`,
|
|
8392
8022
|
file: configPath
|
|
@@ -8401,7 +8031,7 @@ var check20 = {
|
|
|
8401
8031
|
continue;
|
|
8402
8032
|
let css;
|
|
8403
8033
|
try {
|
|
8404
|
-
css = await
|
|
8034
|
+
css = await readFile18(absFile, "utf8");
|
|
8405
8035
|
} catch {
|
|
8406
8036
|
continue;
|
|
8407
8037
|
}
|
|
@@ -8428,7 +8058,7 @@ var check20 = {
|
|
|
8428
8058
|
}
|
|
8429
8059
|
for (const v of violations) {
|
|
8430
8060
|
results.push({
|
|
8431
|
-
checkId:
|
|
8061
|
+
checkId: check21.id,
|
|
8432
8062
|
severity: "warning",
|
|
8433
8063
|
message: v.message,
|
|
8434
8064
|
file: absFile,
|
|
@@ -8440,14 +8070,14 @@ var check20 = {
|
|
|
8440
8070
|
return results;
|
|
8441
8071
|
}
|
|
8442
8072
|
};
|
|
8443
|
-
registerCheck(
|
|
8073
|
+
registerCheck(check21);
|
|
8444
8074
|
|
|
8445
8075
|
// src/checks/source/local-refs.ts
|
|
8446
8076
|
import { existsSync as existsSync10 } from "node:fs";
|
|
8447
8077
|
import { dirname as dirname3, resolve as resolve6 } from "node:path";
|
|
8448
8078
|
|
|
8449
8079
|
// src/checks/source/local-ref-parser.ts
|
|
8450
|
-
import { readFile as
|
|
8080
|
+
import { readFile as readFile19 } from "node:fs/promises";
|
|
8451
8081
|
function newlineOffsets(content) {
|
|
8452
8082
|
const offsets = [];
|
|
8453
8083
|
for (let i = 0;i < content.length; i++)
|
|
@@ -8516,7 +8146,7 @@ async function* renderedLocalRefs(ctx, checkId, results) {
|
|
|
8516
8146
|
for (const file of files) {
|
|
8517
8147
|
let refs;
|
|
8518
8148
|
try {
|
|
8519
|
-
refs = collectRenderedLocalRefs(await
|
|
8149
|
+
refs = collectRenderedLocalRefs(await readFile19(file, "utf8"));
|
|
8520
8150
|
} catch {
|
|
8521
8151
|
results.push(inspectionFailed(checkId, `Could not read source file: ${file}`, { file }));
|
|
8522
8152
|
continue;
|
|
@@ -8527,7 +8157,7 @@ async function* renderedLocalRefs(ctx, checkId, results) {
|
|
|
8527
8157
|
}
|
|
8528
8158
|
|
|
8529
8159
|
// src/checks/source/local-refs.ts
|
|
8530
|
-
var
|
|
8160
|
+
var check22 = {
|
|
8531
8161
|
id: "source.links.local-refs",
|
|
8532
8162
|
name: "Local Markdown References",
|
|
8533
8163
|
description: "Checks local markdown links and image refs resolve on disk",
|
|
@@ -8535,12 +8165,12 @@ var check21 = {
|
|
|
8535
8165
|
phase: "pre-build",
|
|
8536
8166
|
async run(ctx) {
|
|
8537
8167
|
const results = [];
|
|
8538
|
-
for await (const { ref, kind, line, file } of renderedLocalRefs(ctx,
|
|
8168
|
+
for await (const { ref, kind, line, file } of renderedLocalRefs(ctx, check22.id, results)) {
|
|
8539
8169
|
if (isNonFilesystemRef(ref))
|
|
8540
8170
|
continue;
|
|
8541
8171
|
const escape = kind === "image" ? proseImageRefError(ref, ctx.inputDir) : null;
|
|
8542
8172
|
if (escape) {
|
|
8543
|
-
results.push(finding(
|
|
8173
|
+
results.push(finding(check22.id, {
|
|
8544
8174
|
severity: "error",
|
|
8545
8175
|
message: escape,
|
|
8546
8176
|
file,
|
|
@@ -8550,7 +8180,7 @@ var check21 = {
|
|
|
8550
8180
|
}
|
|
8551
8181
|
if (localRefExists(ref, kind, file, ctx.inputDir))
|
|
8552
8182
|
continue;
|
|
8553
|
-
results.push(finding(
|
|
8183
|
+
results.push(finding(check22.id, {
|
|
8554
8184
|
severity: kind === "image" ? "warning" : "error",
|
|
8555
8185
|
code: kind === "image" ? "missing-image-placeholder" : undefined,
|
|
8556
8186
|
message: kind === "image" ? `Local image not found; build will substitute a magenta placeholder: ${ref}` : `Local reference not found: ${ref}`,
|
|
@@ -8575,7 +8205,7 @@ function localRefExists(ref, kind, sourceFile, projectRoot) {
|
|
|
8575
8205
|
return existsSync10(fileRelative);
|
|
8576
8206
|
}
|
|
8577
8207
|
}
|
|
8578
|
-
registerCheck(
|
|
8208
|
+
registerCheck(check22);
|
|
8579
8209
|
|
|
8580
8210
|
// src/lib/build-staging.ts
|
|
8581
8211
|
import path11 from "node:path";
|
|
@@ -8841,7 +8471,7 @@ async function createStageRoot() {
|
|
|
8841
8471
|
}
|
|
8842
8472
|
|
|
8843
8473
|
// src/checks/source/dangling-links.ts
|
|
8844
|
-
var
|
|
8474
|
+
var check23 = {
|
|
8845
8475
|
id: "source.links.dangling",
|
|
8846
8476
|
name: "Dangling Links",
|
|
8847
8477
|
description: "Flags relative links the printed book cannot open (their href is dropped at print time)",
|
|
@@ -8849,10 +8479,10 @@ var check22 = {
|
|
|
8849
8479
|
phase: "pre-build",
|
|
8850
8480
|
async run(ctx) {
|
|
8851
8481
|
const results = [];
|
|
8852
|
-
for await (const { ref, kind, line, file } of renderedLocalRefs(ctx,
|
|
8482
|
+
for await (const { ref, kind, line, file } of renderedLocalRefs(ctx, check23.id, results)) {
|
|
8853
8483
|
if (kind !== "link" || isPrintResolvableHref(ref))
|
|
8854
8484
|
continue;
|
|
8855
|
-
results.push(finding(
|
|
8485
|
+
results.push(finding(check23.id, {
|
|
8856
8486
|
severity: "warning",
|
|
8857
8487
|
code: "dangling-link",
|
|
8858
8488
|
data: { ref },
|
|
@@ -8864,11 +8494,11 @@ var check22 = {
|
|
|
8864
8494
|
return results;
|
|
8865
8495
|
}
|
|
8866
8496
|
};
|
|
8867
|
-
registerCheck(
|
|
8497
|
+
registerCheck(check23);
|
|
8868
8498
|
|
|
8869
8499
|
// src/checks/source/accessibility-alt-text.ts
|
|
8870
|
-
import { readFile as
|
|
8871
|
-
var
|
|
8500
|
+
import { readFile as readFile20 } from "node:fs/promises";
|
|
8501
|
+
var check24 = {
|
|
8872
8502
|
id: "source.accessibility.alt-text",
|
|
8873
8503
|
name: "Image Alt Text",
|
|
8874
8504
|
description: "Checks markdown images include non-empty alt text",
|
|
@@ -8881,7 +8511,7 @@ var check23 = {
|
|
|
8881
8511
|
const results = [];
|
|
8882
8512
|
for (const file of files) {
|
|
8883
8513
|
try {
|
|
8884
|
-
const content = await
|
|
8514
|
+
const content = await readFile20(file, "utf8");
|
|
8885
8515
|
const lines = content.split(`
|
|
8886
8516
|
`);
|
|
8887
8517
|
let inFence = false;
|
|
@@ -8897,7 +8527,7 @@ var check23 = {
|
|
|
8897
8527
|
if (alt.trim())
|
|
8898
8528
|
continue;
|
|
8899
8529
|
results.push({
|
|
8900
|
-
checkId:
|
|
8530
|
+
checkId: check24.id,
|
|
8901
8531
|
severity: "warning",
|
|
8902
8532
|
message: "Image is missing alt text",
|
|
8903
8533
|
file,
|
|
@@ -8922,11 +8552,11 @@ function extractImageAlts(line) {
|
|
|
8922
8552
|
}
|
|
8923
8553
|
return alts;
|
|
8924
8554
|
}
|
|
8925
|
-
registerCheck(
|
|
8555
|
+
registerCheck(check24);
|
|
8926
8556
|
|
|
8927
8557
|
// src/checks/source/accessibility-heading-order.ts
|
|
8928
|
-
import { readFile as
|
|
8929
|
-
var
|
|
8558
|
+
import { readFile as readFile21 } from "node:fs/promises";
|
|
8559
|
+
var check25 = {
|
|
8930
8560
|
id: "source.accessibility.heading-order",
|
|
8931
8561
|
name: "Heading Order",
|
|
8932
8562
|
description: "Checks markdown heading levels do not jump by more than one",
|
|
@@ -8939,7 +8569,7 @@ var check24 = {
|
|
|
8939
8569
|
const results = [];
|
|
8940
8570
|
for (const file of files) {
|
|
8941
8571
|
try {
|
|
8942
|
-
const content = await
|
|
8572
|
+
const content = await readFile21(file, "utf8");
|
|
8943
8573
|
const lines = content.split(`
|
|
8944
8574
|
`);
|
|
8945
8575
|
let inFence = false;
|
|
@@ -8954,7 +8584,7 @@ var check24 = {
|
|
|
8954
8584
|
if (inFence)
|
|
8955
8585
|
continue;
|
|
8956
8586
|
const comment = /^\s*<!--(.*)-->\s*$/.exec(line);
|
|
8957
|
-
if (comment && parseDisableDirective(comment[1])?.includes(
|
|
8587
|
+
if (comment && parseDisableDirective(comment[1])?.includes(check25.id)) {
|
|
8958
8588
|
silencedLine = i + 1;
|
|
8959
8589
|
continue;
|
|
8960
8590
|
}
|
|
@@ -8964,7 +8594,7 @@ var check24 = {
|
|
|
8964
8594
|
const level = match[1].length;
|
|
8965
8595
|
if (prevLevel != null && level > prevLevel + 1 && i !== silencedLine) {
|
|
8966
8596
|
results.push({
|
|
8967
|
-
checkId:
|
|
8597
|
+
checkId: check25.id,
|
|
8968
8598
|
severity: "warning",
|
|
8969
8599
|
message: `Heading level jump from h${prevLevel} to h${level}`,
|
|
8970
8600
|
file,
|
|
@@ -8978,11 +8608,11 @@ var check24 = {
|
|
|
8978
8608
|
return results;
|
|
8979
8609
|
}
|
|
8980
8610
|
};
|
|
8981
|
-
registerCheck(
|
|
8611
|
+
registerCheck(check25);
|
|
8982
8612
|
|
|
8983
8613
|
// src/checks/source/layout-markers.ts
|
|
8984
|
-
import { readFile as
|
|
8985
|
-
var
|
|
8614
|
+
import { readFile as readFile22 } from "node:fs/promises";
|
|
8615
|
+
var check26 = {
|
|
8986
8616
|
id: "source.markdown.layout-markers",
|
|
8987
8617
|
name: "Layout Markers",
|
|
8988
8618
|
description: "Reports @page/@section/@chapter marker arguments Gutterpress could not understand, plus any unknown gp-* class",
|
|
@@ -8994,16 +8624,16 @@ var check25 = {
|
|
|
8994
8624
|
return [];
|
|
8995
8625
|
const results = [];
|
|
8996
8626
|
const plugins = await loadPlugins(ctx.config.extensions, ctx.inputDir, (ref, error2) => {
|
|
8997
|
-
results.push(inspectionFailed(
|
|
8627
|
+
results.push(inspectionFailed(check26.id, `Plugin "${ref}" could not be loaded, so markers it defines were not checked: ${error2.message}`));
|
|
8998
8628
|
});
|
|
8999
8629
|
const md = createMarkdownRenderer(plugins);
|
|
9000
8630
|
for (const file of files) {
|
|
9001
8631
|
try {
|
|
9002
|
-
const content = await
|
|
8632
|
+
const content = await readFile22(file, "utf8");
|
|
9003
8633
|
const env = {};
|
|
9004
8634
|
md.render(content, env);
|
|
9005
8635
|
for (const w of env.layoutWarnings ?? []) {
|
|
9006
|
-
results.push(finding(
|
|
8636
|
+
results.push(finding(check26.id, {
|
|
9007
8637
|
severity: w.severity ?? "warning",
|
|
9008
8638
|
message: w.message,
|
|
9009
8639
|
file,
|
|
@@ -9012,16 +8642,16 @@ var check25 = {
|
|
|
9012
8642
|
}));
|
|
9013
8643
|
}
|
|
9014
8644
|
} catch (error2) {
|
|
9015
|
-
results.push(inspectionFailed(
|
|
8645
|
+
results.push(inspectionFailed(check26.id, `Could not check layout markers in ${file}: ${error2 instanceof Error ? error2.message : String(error2)}`, { file }));
|
|
9016
8646
|
}
|
|
9017
8647
|
}
|
|
9018
8648
|
return results;
|
|
9019
8649
|
}
|
|
9020
8650
|
};
|
|
9021
|
-
registerCheck(
|
|
8651
|
+
registerCheck(check26);
|
|
9022
8652
|
|
|
9023
8653
|
// src/checks/source/merge-markers.ts
|
|
9024
|
-
import { readFile as
|
|
8654
|
+
import { readFile as readFile23 } from "node:fs/promises";
|
|
9025
8655
|
import path12 from "node:path";
|
|
9026
8656
|
|
|
9027
8657
|
// src/checks/asset/extensions.ts
|
|
@@ -9051,7 +8681,7 @@ var CLOSE_SENTINEL = ">>>>>>> online version";
|
|
|
9051
8681
|
function withoutOnlineTag(relPath) {
|
|
9052
8682
|
return relPath.replace(/\.online(?=\.[^./]*$|$)/, "");
|
|
9053
8683
|
}
|
|
9054
|
-
var
|
|
8684
|
+
var check27 = {
|
|
9055
8685
|
id: "source.sync.merge-markers",
|
|
9056
8686
|
name: "Combined Versions",
|
|
9057
8687
|
description: "Finds passages and files still holding two versions (yours and the online copy) after a sync",
|
|
@@ -9063,9 +8693,9 @@ var check26 = {
|
|
|
9063
8693
|
for (const file of textFiles) {
|
|
9064
8694
|
let content;
|
|
9065
8695
|
try {
|
|
9066
|
-
content = await
|
|
8696
|
+
content = await readFile23(file, "utf8");
|
|
9067
8697
|
} catch {
|
|
9068
|
-
results.push(inspectionFailed(
|
|
8698
|
+
results.push(inspectionFailed(check27.id, `Could not read source file: ${file}`, { file }));
|
|
9069
8699
|
continue;
|
|
9070
8700
|
}
|
|
9071
8701
|
if (!content.includes(OPEN_SENTINEL) && !content.includes(CLOSE_SENTINEL))
|
|
@@ -9077,7 +8707,7 @@ var check26 = {
|
|
|
9077
8707
|
const line = lines[i].endsWith("\r") ? lines[i].slice(0, -1) : lines[i];
|
|
9078
8708
|
if (line === OPEN_SENTINEL) {
|
|
9079
8709
|
inBlock = true;
|
|
9080
|
-
results.push(finding(
|
|
8710
|
+
results.push(finding(check27.id, {
|
|
9081
8711
|
severity: "error",
|
|
9082
8712
|
code: "two-versions-passage",
|
|
9083
8713
|
message: "This passage has two versions (yours and the online copy) — keep what you want, then delete the marker lines.",
|
|
@@ -9086,7 +8716,7 @@ var check26 = {
|
|
|
9086
8716
|
}));
|
|
9087
8717
|
} else if (line === CLOSE_SENTINEL) {
|
|
9088
8718
|
if (!inBlock) {
|
|
9089
|
-
results.push(finding(
|
|
8719
|
+
results.push(finding(check27.id, {
|
|
9090
8720
|
severity: "error",
|
|
9091
8721
|
code: "leftover-version-marker",
|
|
9092
8722
|
message: "This marker line is left over from combining two versions — delete it.",
|
|
@@ -9107,7 +8737,7 @@ var check26 = {
|
|
|
9107
8737
|
});
|
|
9108
8738
|
for (const sibling of siblings.sort()) {
|
|
9109
8739
|
const rel = path12.relative(ctx.inputDir, sibling).split(path12.sep).join("/");
|
|
9110
|
-
results.push(finding(
|
|
8740
|
+
results.push(finding(check27.id, {
|
|
9111
8741
|
severity: "warning",
|
|
9112
8742
|
code: "kept-both-versions",
|
|
9113
8743
|
message: `Two versions of ${withoutOnlineTag(rel)} are in your book — keep the one you want, then delete the other.`,
|
|
@@ -9115,18 +8745,18 @@ var check26 = {
|
|
|
9115
8745
|
}));
|
|
9116
8746
|
}
|
|
9117
8747
|
} catch (error2) {
|
|
9118
|
-
results.push(inspectionFailed(
|
|
8748
|
+
results.push(inspectionFailed(check27.id, `Could not scan for kept-both files: ${error2 instanceof Error ? error2.message : String(error2)}`));
|
|
9119
8749
|
}
|
|
9120
8750
|
return results;
|
|
9121
8751
|
}
|
|
9122
8752
|
};
|
|
9123
|
-
registerCheck(
|
|
8753
|
+
registerCheck(check27);
|
|
9124
8754
|
|
|
9125
8755
|
// src/checks/asset/image-file-size.ts
|
|
9126
8756
|
import { stat as stat4 } from "node:fs/promises";
|
|
9127
8757
|
|
|
9128
8758
|
// src/lib/image-inspect.ts
|
|
9129
|
-
import { stat as stat3, readFile as
|
|
8759
|
+
import { stat as stat3, readFile as readFile24 } from "node:fs/promises";
|
|
9130
8760
|
var DEFAULT_DPI = 72;
|
|
9131
8761
|
var cache = new Map;
|
|
9132
8762
|
async function inspectImage(path13) {
|
|
@@ -9141,7 +8771,7 @@ async function inspectImage(path13) {
|
|
|
9141
8771
|
return hit.info;
|
|
9142
8772
|
let info2 = null;
|
|
9143
8773
|
try {
|
|
9144
|
-
const buf = await
|
|
8774
|
+
const buf = await readFile24(path13);
|
|
9145
8775
|
info2 = parseImage(buf);
|
|
9146
8776
|
} catch {
|
|
9147
8777
|
info2 = null;
|
|
@@ -9346,7 +8976,7 @@ async function collectImageFiles(dirs, exts, ignore2 = ASSET_SCAN_IGNORE_GLOBS)
|
|
|
9346
8976
|
}
|
|
9347
8977
|
|
|
9348
8978
|
// src/checks/asset/image-file-size.ts
|
|
9349
|
-
var
|
|
8979
|
+
var check28 = {
|
|
9350
8980
|
id: "asset.image.file-size",
|
|
9351
8981
|
name: "Image File Size",
|
|
9352
8982
|
description: "Checks that image files do not exceed the maximum size limit",
|
|
@@ -9367,14 +8997,14 @@ var check27 = {
|
|
|
9367
8997
|
if (info2.size > maxSize) {
|
|
9368
8998
|
const sizeMb = (info2.size / 1e6).toFixed(1);
|
|
9369
8999
|
const maxMb = (maxSize / 1e6).toFixed(1);
|
|
9370
|
-
results.push(finding(
|
|
9000
|
+
results.push(finding(check28.id, {
|
|
9371
9001
|
severity: "warning",
|
|
9372
9002
|
message: `Image file too large: ${sizeMb}MB (max ${maxMb}MB)`,
|
|
9373
9003
|
file
|
|
9374
9004
|
}));
|
|
9375
9005
|
}
|
|
9376
9006
|
} catch {
|
|
9377
|
-
results.push(inspectionFailed(
|
|
9007
|
+
results.push(inspectionFailed(check28.id, `Could not stat image file: ${file}`, {
|
|
9378
9008
|
file
|
|
9379
9009
|
}));
|
|
9380
9010
|
}
|
|
@@ -9382,10 +9012,10 @@ var check27 = {
|
|
|
9382
9012
|
return results;
|
|
9383
9013
|
}
|
|
9384
9014
|
};
|
|
9385
|
-
registerCheck(
|
|
9015
|
+
registerCheck(check28);
|
|
9386
9016
|
|
|
9387
9017
|
// src/checks/asset/image-resolution.ts
|
|
9388
|
-
var
|
|
9018
|
+
var check29 = {
|
|
9389
9019
|
id: "asset.image.resolution",
|
|
9390
9020
|
name: "Image Resolution",
|
|
9391
9021
|
description: "Checks source image DPI from embedded density metadata",
|
|
@@ -9407,7 +9037,7 @@ var check28 = {
|
|
|
9407
9037
|
const { xDpi, yDpi } = info2;
|
|
9408
9038
|
if (xDpi > 0 && yDpi > 0 && (xDpi < minDpi || yDpi < minDpi)) {
|
|
9409
9039
|
results.push({
|
|
9410
|
-
checkId:
|
|
9040
|
+
checkId: check29.id,
|
|
9411
9041
|
severity: "warning",
|
|
9412
9042
|
message: `Image resolution too low: ${xDpi}x${yDpi} DPI (minimum ${minDpi} DPI)`,
|
|
9413
9043
|
file
|
|
@@ -9417,7 +9047,7 @@ var check28 = {
|
|
|
9417
9047
|
return results;
|
|
9418
9048
|
}
|
|
9419
9049
|
};
|
|
9420
|
-
registerCheck(
|
|
9050
|
+
registerCheck(check29);
|
|
9421
9051
|
|
|
9422
9052
|
// src/checks/asset/image-color-space.ts
|
|
9423
9053
|
var LABEL = {
|
|
@@ -9425,7 +9055,7 @@ var LABEL = {
|
|
|
9425
9055
|
gray: "Gray",
|
|
9426
9056
|
cmyk: "CMYK"
|
|
9427
9057
|
};
|
|
9428
|
-
var
|
|
9058
|
+
var check30 = {
|
|
9429
9059
|
id: "asset.image.color-space",
|
|
9430
9060
|
name: "Image Color Space",
|
|
9431
9061
|
description: "Validates image color spaces against allowed list",
|
|
@@ -9446,7 +9076,7 @@ var check29 = {
|
|
|
9446
9076
|
const cs = info2?.colorSpace;
|
|
9447
9077
|
if (cs && !allowedLower.has(cs)) {
|
|
9448
9078
|
results.push({
|
|
9449
|
-
checkId:
|
|
9079
|
+
checkId: check30.id,
|
|
9450
9080
|
severity: "warning",
|
|
9451
9081
|
message: `Image uses ${LABEL[cs] ?? cs} color space (allowed: ${allowed.join(", ")})`,
|
|
9452
9082
|
file
|
|
@@ -9456,10 +9086,10 @@ var check29 = {
|
|
|
9456
9086
|
return results;
|
|
9457
9087
|
}
|
|
9458
9088
|
};
|
|
9459
|
-
registerCheck(
|
|
9089
|
+
registerCheck(check30);
|
|
9460
9090
|
|
|
9461
9091
|
// src/checks/asset/image-alpha.ts
|
|
9462
|
-
var
|
|
9092
|
+
var check31 = {
|
|
9463
9093
|
id: "asset.image.alpha-channel",
|
|
9464
9094
|
name: "Image Alpha Channel",
|
|
9465
9095
|
description: "Checks for alpha channels in PNG/TIFF images",
|
|
@@ -9477,7 +9107,7 @@ var check30 = {
|
|
|
9477
9107
|
const info2 = await inspectImage(file);
|
|
9478
9108
|
if (info2?.hasAlpha) {
|
|
9479
9109
|
results.push({
|
|
9480
|
-
checkId:
|
|
9110
|
+
checkId: check31.id,
|
|
9481
9111
|
severity: "warning",
|
|
9482
9112
|
message: "Image contains alpha channel, which may cause print issues",
|
|
9483
9113
|
file
|
|
@@ -9487,10 +9117,10 @@ var check30 = {
|
|
|
9487
9117
|
return results;
|
|
9488
9118
|
}
|
|
9489
9119
|
};
|
|
9490
|
-
registerCheck(
|
|
9120
|
+
registerCheck(check31);
|
|
9491
9121
|
|
|
9492
9122
|
// src/checks/asset/image-tac.ts
|
|
9493
|
-
var
|
|
9123
|
+
var check32 = {
|
|
9494
9124
|
id: "asset.image.tac-raster",
|
|
9495
9125
|
name: "Image TAC (Raster)",
|
|
9496
9126
|
description: "Rasterizes and checks TAC per image using Ghostscript",
|
|
@@ -9509,7 +9139,7 @@ var check31 = {
|
|
|
9509
9139
|
const ghostscript = await resolveGhostscript();
|
|
9510
9140
|
if (!ghostscript) {
|
|
9511
9141
|
return [
|
|
9512
|
-
inspectionFailed(
|
|
9142
|
+
inspectionFailed(check32.id, "Could not inspect image ink coverage: Ghostscript executable not found")
|
|
9513
9143
|
];
|
|
9514
9144
|
}
|
|
9515
9145
|
for (const file of files) {
|
|
@@ -9527,7 +9157,7 @@ var check31 = {
|
|
|
9527
9157
|
if (nums.length === 4 && nums.every((n) => Number.isFinite(n))) {
|
|
9528
9158
|
const tac = (nums[0] + nums[1] + nums[2] + nums[3]) * 100;
|
|
9529
9159
|
if (tac > maxTac) {
|
|
9530
|
-
results.push(finding(
|
|
9160
|
+
results.push(finding(check32.id, {
|
|
9531
9161
|
severity: "warning",
|
|
9532
9162
|
message: `Image TAC exceeds limit: ${tac.toFixed(1)}% (max ${maxTac}%)`,
|
|
9533
9163
|
file,
|
|
@@ -9539,16 +9169,16 @@ var check31 = {
|
|
|
9539
9169
|
}
|
|
9540
9170
|
}
|
|
9541
9171
|
} catch {
|
|
9542
|
-
results.push(inspectionFailed(
|
|
9172
|
+
results.push(inspectionFailed(check32.id, `Could not inspect image ink coverage: ${file}`, { file }));
|
|
9543
9173
|
}
|
|
9544
9174
|
}
|
|
9545
9175
|
return results;
|
|
9546
9176
|
}
|
|
9547
9177
|
};
|
|
9548
|
-
registerCheck(
|
|
9178
|
+
registerCheck(check32);
|
|
9549
9179
|
|
|
9550
9180
|
// src/checks/asset/approved-fonts.ts
|
|
9551
|
-
var
|
|
9181
|
+
var check33 = {
|
|
9552
9182
|
id: "asset.font.approved-files",
|
|
9553
9183
|
name: "Approved Font Files",
|
|
9554
9184
|
description: "Checks font files against the approved file patterns",
|
|
@@ -9587,7 +9217,7 @@ var check32 = {
|
|
|
9587
9217
|
for (const font of allFonts) {
|
|
9588
9218
|
if (!approvedFonts.has(font)) {
|
|
9589
9219
|
results.push({
|
|
9590
|
-
checkId:
|
|
9220
|
+
checkId: check33.id,
|
|
9591
9221
|
severity: "warning",
|
|
9592
9222
|
message: "Font file not in approved list",
|
|
9593
9223
|
file: font
|
|
@@ -9597,7 +9227,7 @@ var check32 = {
|
|
|
9597
9227
|
return results;
|
|
9598
9228
|
}
|
|
9599
9229
|
};
|
|
9600
|
-
registerCheck(
|
|
9230
|
+
registerCheck(check33);
|
|
9601
9231
|
|
|
9602
9232
|
// src/checks/asset/font-license.ts
|
|
9603
9233
|
import { existsSync as existsSync11 } from "node:fs";
|
|
@@ -9612,7 +9242,7 @@ var LICENSE_NAMES = [
|
|
|
9612
9242
|
"OFL-1.1.txt",
|
|
9613
9243
|
"COPYING"
|
|
9614
9244
|
];
|
|
9615
|
-
var
|
|
9245
|
+
var check34 = {
|
|
9616
9246
|
id: "asset.font.license",
|
|
9617
9247
|
name: "Font License",
|
|
9618
9248
|
description: "Checks for license files in font directories",
|
|
@@ -9639,7 +9269,7 @@ var check33 = {
|
|
|
9639
9269
|
const hasLicense = LICENSE_NAMES.some((name) => existsSync11(resolve7(fontDir, name)));
|
|
9640
9270
|
if (!hasLicense) {
|
|
9641
9271
|
results.push({
|
|
9642
|
-
checkId:
|
|
9272
|
+
checkId: check34.id,
|
|
9643
9273
|
severity: "warning",
|
|
9644
9274
|
message: `No font license file found in directory`,
|
|
9645
9275
|
file: fontDir
|
|
@@ -9649,10 +9279,10 @@ var check33 = {
|
|
|
9649
9279
|
return results;
|
|
9650
9280
|
}
|
|
9651
9281
|
};
|
|
9652
|
-
registerCheck(
|
|
9282
|
+
registerCheck(check34);
|
|
9653
9283
|
|
|
9654
9284
|
// src/checks/heuristic/text-density.ts
|
|
9655
|
-
var
|
|
9285
|
+
var check35 = {
|
|
9656
9286
|
id: "heuristic.whitespace.text-density",
|
|
9657
9287
|
name: "Text Density",
|
|
9658
9288
|
description: "Checks characters-per-page ratio",
|
|
@@ -9681,7 +9311,7 @@ var check34 = {
|
|
|
9681
9311
|
});
|
|
9682
9312
|
if (lowPages.length > 0) {
|
|
9683
9313
|
results.push({
|
|
9684
|
-
checkId:
|
|
9314
|
+
checkId: check35.id,
|
|
9685
9315
|
severity: "info",
|
|
9686
9316
|
message: `Low text density on pages: ${lowPages.join(", ")} (below ${range.min} chars)`,
|
|
9687
9317
|
file: ctx.pdfPath
|
|
@@ -9689,7 +9319,7 @@ var check34 = {
|
|
|
9689
9319
|
}
|
|
9690
9320
|
if (highPages.length > 0) {
|
|
9691
9321
|
results.push({
|
|
9692
|
-
checkId:
|
|
9322
|
+
checkId: check35.id,
|
|
9693
9323
|
severity: "info",
|
|
9694
9324
|
message: `High text density on pages: ${highPages.join(", ")} (above ${range.max} chars)`,
|
|
9695
9325
|
file: ctx.pdfPath
|
|
@@ -9698,11 +9328,11 @@ var check34 = {
|
|
|
9698
9328
|
return results;
|
|
9699
9329
|
}
|
|
9700
9330
|
};
|
|
9701
|
-
registerCheck(
|
|
9331
|
+
registerCheck(check35);
|
|
9702
9332
|
|
|
9703
9333
|
// src/checks/heuristic/section-density.ts
|
|
9704
|
-
import { readFile as
|
|
9705
|
-
var
|
|
9334
|
+
import { readFile as readFile25 } from "node:fs/promises";
|
|
9335
|
+
var check36 = {
|
|
9706
9336
|
id: "heuristic.chunking.section-density",
|
|
9707
9337
|
name: "Section Density",
|
|
9708
9338
|
description: "Checks heading/paragraph/callout density from source Markdown",
|
|
@@ -9718,7 +9348,7 @@ var check35 = {
|
|
|
9718
9348
|
const results = [];
|
|
9719
9349
|
for (const file of files) {
|
|
9720
9350
|
try {
|
|
9721
|
-
const content = await
|
|
9351
|
+
const content = await readFile25(file, "utf8");
|
|
9722
9352
|
const lines = content.split(`
|
|
9723
9353
|
`);
|
|
9724
9354
|
let currentSectionStart = 0;
|
|
@@ -9728,7 +9358,7 @@ var check35 = {
|
|
|
9728
9358
|
const line = lines[i];
|
|
9729
9359
|
if (/^#{1,6}\s/.test(line)) {
|
|
9730
9360
|
if (paragraphCount > maxParas) {
|
|
9731
|
-
results.push(finding(
|
|
9361
|
+
results.push(finding(check36.id, {
|
|
9732
9362
|
severity: "info",
|
|
9733
9363
|
message: `Section has ${paragraphCount} paragraphs (max recommended: ${maxParas})`,
|
|
9734
9364
|
file,
|
|
@@ -9748,7 +9378,7 @@ var check35 = {
|
|
|
9748
9378
|
}
|
|
9749
9379
|
}
|
|
9750
9380
|
if (paragraphCount > maxParas) {
|
|
9751
|
-
results.push(finding(
|
|
9381
|
+
results.push(finding(check36.id, {
|
|
9752
9382
|
severity: "info",
|
|
9753
9383
|
message: `Section has ${paragraphCount} paragraphs (max recommended: ${maxParas})`,
|
|
9754
9384
|
file,
|
|
@@ -9756,7 +9386,7 @@ var check35 = {
|
|
|
9756
9386
|
}));
|
|
9757
9387
|
}
|
|
9758
9388
|
} catch {
|
|
9759
|
-
results.push(inspectionFailed(
|
|
9389
|
+
results.push(inspectionFailed(check36.id, `Could not read source file: ${file}`, {
|
|
9760
9390
|
file
|
|
9761
9391
|
}));
|
|
9762
9392
|
}
|
|
@@ -9764,10 +9394,10 @@ var check35 = {
|
|
|
9764
9394
|
return results;
|
|
9765
9395
|
}
|
|
9766
9396
|
};
|
|
9767
|
-
registerCheck(
|
|
9397
|
+
registerCheck(check36);
|
|
9768
9398
|
|
|
9769
9399
|
// src/checks/heuristic/layer-count.ts
|
|
9770
|
-
var
|
|
9400
|
+
var check37 = {
|
|
9771
9401
|
id: "heuristic.decoration.layer-count",
|
|
9772
9402
|
name: "Layer Count",
|
|
9773
9403
|
description: "Counts image objects per page",
|
|
@@ -9792,7 +9422,7 @@ var check36 = {
|
|
|
9792
9422
|
heavyPages.sort((a, b) => a - b);
|
|
9793
9423
|
return [
|
|
9794
9424
|
{
|
|
9795
|
-
checkId:
|
|
9425
|
+
checkId: check37.id,
|
|
9796
9426
|
severity: "info",
|
|
9797
9427
|
message: `Pages with many image layers (>${maxLayers}): ${heavyPages.join(", ")}`,
|
|
9798
9428
|
file: ctx.pdfPath
|
|
@@ -9802,10 +9432,10 @@ var check36 = {
|
|
|
9802
9432
|
return [];
|
|
9803
9433
|
}
|
|
9804
9434
|
};
|
|
9805
|
-
registerCheck(
|
|
9435
|
+
registerCheck(check37);
|
|
9806
9436
|
|
|
9807
9437
|
// src/checks/heuristic/placement-variance.ts
|
|
9808
|
-
var
|
|
9438
|
+
var check38 = {
|
|
9809
9439
|
id: "heuristic.layout.placement-variance",
|
|
9810
9440
|
name: "Placement Variance",
|
|
9811
9441
|
description: "Analyzes text baseline coordinates for layout consistency",
|
|
@@ -9823,7 +9453,7 @@ var check37 = {
|
|
|
9823
9453
|
const uniqueX = new Set(positions.map((p) => Math.round(p.x)));
|
|
9824
9454
|
return [
|
|
9825
9455
|
{
|
|
9826
|
-
checkId:
|
|
9456
|
+
checkId: check38.id,
|
|
9827
9457
|
severity: "info",
|
|
9828
9458
|
message: `Layout analysis: ${uniqueX.size} unique horizontal text positions across ${positions.length} text blocks.`,
|
|
9829
9459
|
file: ctx.pdfPath
|
|
@@ -9831,7 +9461,7 @@ var check37 = {
|
|
|
9831
9461
|
];
|
|
9832
9462
|
}
|
|
9833
9463
|
};
|
|
9834
|
-
registerCheck(
|
|
9464
|
+
registerCheck(check38);
|
|
9835
9465
|
|
|
9836
9466
|
// src/checks/runner.ts
|
|
9837
9467
|
function getCheckSeverityOverride(checkId, config) {
|
|
@@ -9861,16 +9491,16 @@ async function runChecks(ctx, opts = {}) {
|
|
|
9861
9491
|
}
|
|
9862
9492
|
const release = retainPdfCache();
|
|
9863
9493
|
try {
|
|
9864
|
-
for (const
|
|
9494
|
+
for (const check39 of checks2) {
|
|
9865
9495
|
try {
|
|
9866
|
-
let results = await
|
|
9867
|
-
const severityOverride = getCheckSeverityOverride(
|
|
9496
|
+
let results = await check39.run(ctx);
|
|
9497
|
+
const severityOverride = getCheckSeverityOverride(check39.id, ctx.config);
|
|
9868
9498
|
if (severityOverride) {
|
|
9869
9499
|
for (const r of results) {
|
|
9870
9500
|
r.severity = severityOverride;
|
|
9871
9501
|
}
|
|
9872
9502
|
}
|
|
9873
|
-
const lintLevel = ruleLevel(ctx.config.lint.rules,
|
|
9503
|
+
const lintLevel = ruleLevel(ctx.config.lint.rules, check39.id);
|
|
9874
9504
|
if (lintLevel === "off")
|
|
9875
9505
|
results = [];
|
|
9876
9506
|
else if (lintLevel) {
|
|
@@ -9878,15 +9508,15 @@ async function runChecks(ctx, opts = {}) {
|
|
|
9878
9508
|
r.severity = lintLevel === "warn" ? "warning" : "error";
|
|
9879
9509
|
}
|
|
9880
9510
|
if (results.length === 0) {
|
|
9881
|
-
passed.push(
|
|
9511
|
+
passed.push(check39.id);
|
|
9882
9512
|
} else {
|
|
9883
9513
|
allResults.push(...results);
|
|
9884
9514
|
}
|
|
9885
9515
|
} catch (err) {
|
|
9886
9516
|
allResults.push({
|
|
9887
|
-
checkId:
|
|
9517
|
+
checkId: check39.id,
|
|
9888
9518
|
severity: "error",
|
|
9889
|
-
message: `Check "${
|
|
9519
|
+
message: `Check "${check39.id}" threw: ${err instanceof Error ? err.message : String(err)}`
|
|
9890
9520
|
});
|
|
9891
9521
|
}
|
|
9892
9522
|
}
|
|
@@ -9926,15 +9556,15 @@ function emptyReport() {
|
|
|
9926
9556
|
async function checkToolAvailability(config, opts = {}) {
|
|
9927
9557
|
const { checks: checks2 } = selectChecks(opts, config);
|
|
9928
9558
|
const toolToChecks = new Map;
|
|
9929
|
-
for (const
|
|
9930
|
-
if (!
|
|
9559
|
+
for (const check39 of checks2) {
|
|
9560
|
+
if (!check39.requiredTools?.length)
|
|
9931
9561
|
continue;
|
|
9932
|
-
for (const tool of
|
|
9562
|
+
for (const tool of check39.requiredTools) {
|
|
9933
9563
|
const existing = toolToChecks.get(tool);
|
|
9934
9564
|
if (existing) {
|
|
9935
|
-
existing.push(
|
|
9565
|
+
existing.push(check39.id);
|
|
9936
9566
|
} else {
|
|
9937
|
-
toolToChecks.set(tool, [
|
|
9567
|
+
toolToChecks.set(tool, [check39.id]);
|
|
9938
9568
|
}
|
|
9939
9569
|
}
|
|
9940
9570
|
}
|
|
@@ -9950,11 +9580,11 @@ async function checkToolAvailability(config, opts = {}) {
|
|
|
9950
9580
|
const missing = results.filter((r) => !r.found).map((r) => r.tool);
|
|
9951
9581
|
const missingSet = new Set(missing);
|
|
9952
9582
|
const skippedChecks = [];
|
|
9953
|
-
for (const
|
|
9954
|
-
if (!
|
|
9583
|
+
for (const check39 of checks2) {
|
|
9584
|
+
if (!check39.requiredTools?.length)
|
|
9955
9585
|
continue;
|
|
9956
|
-
if (
|
|
9957
|
-
skippedChecks.push(
|
|
9586
|
+
if (check39.requiredTools.some((t) => missingSet.has(t))) {
|
|
9587
|
+
skippedChecks.push(check39.id);
|
|
9958
9588
|
}
|
|
9959
9589
|
}
|
|
9960
9590
|
return { available, missing, skippedChecks, toolToChecks };
|
|
@@ -10227,7 +9857,7 @@ async function executeValidation(args) {
|
|
|
10227
9857
|
};
|
|
10228
9858
|
if (args.fix) {
|
|
10229
9859
|
const selected = selectChecks(runnerOptions, config).checks;
|
|
10230
|
-
if (selected.some((
|
|
9860
|
+
if (selected.some((check39) => check39.id === MARKDOWNLINT_CHECK_ID)) {
|
|
10231
9861
|
await applyMarkdownlintFixes(context);
|
|
10232
9862
|
} else {
|
|
10233
9863
|
log.warn(`--fix: ${MARKDOWNLINT_CHECK_ID} is not part of this run — no files were fixed.`);
|
|
@@ -10706,7 +10336,7 @@ async function runBuild(opts) {
|
|
|
10706
10336
|
import path16 from "path";
|
|
10707
10337
|
import { tmpdir } from "os";
|
|
10708
10338
|
import { randomBytes as randomBytes2 } from "crypto";
|
|
10709
|
-
import { readdir as readdir5, readFile as
|
|
10339
|
+
import { readdir as readdir5, readFile as readFile26, writeFile as writeFile6 } from "node:fs/promises";
|
|
10710
10340
|
|
|
10711
10341
|
// src/utils/file-utils.ts
|
|
10712
10342
|
import { promises as fs3 } from "fs";
|
|
@@ -11255,7 +10885,7 @@ async function cleanupOrphanTempDirs() {
|
|
|
11255
10885
|
const dir = path16.join(TEMP_DIR_BASE, entry);
|
|
11256
10886
|
const pidFile = path16.join(dir, PID_FILE_NAME);
|
|
11257
10887
|
try {
|
|
11258
|
-
const raw = await
|
|
10888
|
+
const raw = await readFile26(pidFile, "utf8");
|
|
11259
10889
|
const pid = parseInt(raw.trim(), 10);
|
|
11260
10890
|
if (!isProcessAlive(pid)) {
|
|
11261
10891
|
debug(`Removing orphan temp dir ${dir} (pid ${pid} not alive)`);
|
|
@@ -11362,7 +10992,7 @@ function createServerState(inputPath, tempDir, config, options) {
|
|
|
11362
10992
|
import http from "node:http";
|
|
11363
10993
|
import net from "node:net";
|
|
11364
10994
|
import { createHash as createHash5, randomUUID as randomUUID3 } from "node:crypto";
|
|
11365
|
-
import { readFile as
|
|
10995
|
+
import { readFile as readFile27, stat as stat5 } from "node:fs/promises";
|
|
11366
10996
|
import path17 from "path";
|
|
11367
10997
|
import { WebSocket, WebSocketServer } from "ws";
|
|
11368
10998
|
|
|
@@ -11461,7 +11091,7 @@ async function serveStatic(absPath, res, cacheControl = "no-store", extraHeaders
|
|
|
11461
11091
|
}
|
|
11462
11092
|
let data;
|
|
11463
11093
|
try {
|
|
11464
|
-
data = await
|
|
11094
|
+
data = await readFile27(filePath);
|
|
11465
11095
|
} catch {
|
|
11466
11096
|
res.writeHead(404);
|
|
11467
11097
|
res.end("Not Found");
|
|
@@ -11510,7 +11140,7 @@ async function serveRevalidatedStatic(req, absPath, res, validators) {
|
|
|
11510
11140
|
let data;
|
|
11511
11141
|
if (!validator || validator.stamp !== stamp) {
|
|
11512
11142
|
try {
|
|
11513
|
-
data = await
|
|
11143
|
+
data = await readFile27(absPath);
|
|
11514
11144
|
} catch {
|
|
11515
11145
|
await serveStatic(absPath, res);
|
|
11516
11146
|
return;
|
|
@@ -11822,7 +11452,7 @@ async function startPreviewServer(options) {
|
|
|
11822
11452
|
import { platform, arch, release } from "node:os";
|
|
11823
11453
|
|
|
11824
11454
|
// src/lib/remote-auth/token-store.ts
|
|
11825
|
-
import { chmod, mkdir as mkdir7, readFile as
|
|
11455
|
+
import { chmod, mkdir as mkdir7, readFile as readFile28, rename as rename4, writeFile as writeFile7 } from "node:fs/promises";
|
|
11826
11456
|
import os3 from "node:os";
|
|
11827
11457
|
import path18 from "node:path";
|
|
11828
11458
|
function credentialHostKey(hostOrUrl) {
|
|
@@ -11866,7 +11496,7 @@ class FileTokenStore {
|
|
|
11866
11496
|
async read() {
|
|
11867
11497
|
let raw;
|
|
11868
11498
|
try {
|
|
11869
|
-
raw = await
|
|
11499
|
+
raw = await readFile28(this.filePath, "utf8");
|
|
11870
11500
|
} catch (e) {
|
|
11871
11501
|
if (e?.code === "ENOENT") {
|
|
11872
11502
|
return { version: 1, credentials: {} };
|
|
@@ -12066,13 +11696,13 @@ async function getSystemDiagnostics() {
|
|
|
12066
11696
|
};
|
|
12067
11697
|
}
|
|
12068
11698
|
// src/lib/project-scaffold.ts
|
|
12069
|
-
import { access, copyFile, cp as cp2, mkdir as mkdir9, readdir as readdir6, readFile as
|
|
11699
|
+
import { access, copyFile, cp as cp2, mkdir as mkdir9, readdir as readdir6, readFile as readFile30, stat as stat6, writeFile as writeFile9 } from "node:fs/promises";
|
|
12070
11700
|
import { constants as FS, existsSync as existsSync14 } from "node:fs";
|
|
12071
11701
|
import path20 from "node:path";
|
|
12072
11702
|
|
|
12073
11703
|
// src/lib/page-size.ts
|
|
12074
11704
|
import { existsSync as existsSync13 } from "node:fs";
|
|
12075
|
-
import { mkdir as mkdir8, readFile as
|
|
11705
|
+
import { mkdir as mkdir8, readFile as readFile29, writeFile as writeFile8 } from "node:fs/promises";
|
|
12076
11706
|
import path19 from "node:path";
|
|
12077
11707
|
import postcss4 from "postcss";
|
|
12078
11708
|
import { Scalar as Scalar2 } from "yaml";
|
|
@@ -12177,7 +11807,7 @@ var relDisplay2 = (projectDir, abs) => path19.relative(projectDir, abs).split(pa
|
|
|
12177
11807
|
async function findCssSize(projectDir, sheets) {
|
|
12178
11808
|
let found = null;
|
|
12179
11809
|
for (const file of sheets) {
|
|
12180
|
-
const size = readPageSizeFromCss(await
|
|
11810
|
+
const size = readPageSizeFromCss(await readFile29(file, "utf8"));
|
|
12181
11811
|
if (size)
|
|
12182
11812
|
found = { file, size };
|
|
12183
11813
|
}
|
|
@@ -12204,7 +11834,7 @@ async function setPageSetup(projectDir, choice) {
|
|
|
12204
11834
|
const found = await findCssSize(projectDir, sheets);
|
|
12205
11835
|
const newSheet = path19.join(projectDir, "styles", "book.css");
|
|
12206
11836
|
const target = found?.file ?? sheets[sheets.length - 1] ?? newSheet;
|
|
12207
|
-
const before = existsSync13(target) ? await
|
|
11837
|
+
const before = existsSync13(target) ? await readFile29(target, "utf8") : "";
|
|
12208
11838
|
let after;
|
|
12209
11839
|
try {
|
|
12210
11840
|
after = setPageSizeInCss(before, size);
|
|
@@ -12494,7 +12124,7 @@ styles:
|
|
|
12494
12124
|
async function firstSourceFile(manifestPath) {
|
|
12495
12125
|
let text;
|
|
12496
12126
|
try {
|
|
12497
|
-
text = await
|
|
12127
|
+
text = await readFile30(manifestPath, "utf8");
|
|
12498
12128
|
} catch {
|
|
12499
12129
|
return;
|
|
12500
12130
|
}
|
|
@@ -12506,14 +12136,14 @@ async function firstSourceFile(manifestPath) {
|
|
|
12506
12136
|
return m ? m[1].trim() : undefined;
|
|
12507
12137
|
}
|
|
12508
12138
|
async function fillTemplateFile(filePath, substitutions) {
|
|
12509
|
-
let text = await
|
|
12139
|
+
let text = await readFile30(filePath, "utf8");
|
|
12510
12140
|
for (const [token, value] of Object.entries(substitutions)) {
|
|
12511
12141
|
text = text.split(token).join(value);
|
|
12512
12142
|
}
|
|
12513
12143
|
await writeFile9(filePath, text, "utf8");
|
|
12514
12144
|
}
|
|
12515
12145
|
// src/lib/extension-scaffold.ts
|
|
12516
|
-
import { access as access2, mkdir as mkdir10, readFile as
|
|
12146
|
+
import { access as access2, mkdir as mkdir10, readFile as readFile31, writeFile as writeFile10 } from "node:fs/promises";
|
|
12517
12147
|
import { constants as FS2 } from "node:fs";
|
|
12518
12148
|
import path21 from "node:path";
|
|
12519
12149
|
var EXTENSION_KINDS = ["plugin", "theme"];
|
|
@@ -12630,7 +12260,7 @@ async function scaffoldExtension(options) {
|
|
|
12630
12260
|
const src = await getAssetPath(`extension-templates/${kind}/${assetName}`);
|
|
12631
12261
|
const dest = path21.join(extensionDir, relDest);
|
|
12632
12262
|
await mkdir10(path21.dirname(dest), { recursive: true });
|
|
12633
|
-
const text = await
|
|
12263
|
+
const text = await readFile31(src, "utf8");
|
|
12634
12264
|
const table = relDest.endsWith(".json") ? jsonSafe : plain;
|
|
12635
12265
|
await writeFile10(dest, substitute(text, table), "utf8");
|
|
12636
12266
|
written.push(relDest);
|
|
@@ -12656,7 +12286,7 @@ function substitute(text, table) {
|
|
|
12656
12286
|
return out;
|
|
12657
12287
|
}
|
|
12658
12288
|
// src/lib/project-templates.ts
|
|
12659
|
-
import { cp as cp3, mkdir as mkdir11, readFile as
|
|
12289
|
+
import { cp as cp3, mkdir as mkdir11, readFile as readFile32, readdir as readdir7, stat as stat7, writeFile as writeFile11 } from "node:fs/promises";
|
|
12660
12290
|
import { constants as FS3, existsSync as existsSync15 } from "node:fs";
|
|
12661
12291
|
import { access as access3 } from "node:fs/promises";
|
|
12662
12292
|
import path22 from "node:path";
|
|
@@ -12668,7 +12298,7 @@ var BUILT_IN_TEMPLATE_IDS = [
|
|
|
12668
12298
|
];
|
|
12669
12299
|
async function readTemplateChoices(manifestPath) {
|
|
12670
12300
|
try {
|
|
12671
|
-
const text = await
|
|
12301
|
+
const text = await readFile32(manifestPath, "utf8");
|
|
12672
12302
|
const doc = parseDocument2(text);
|
|
12673
12303
|
const out = {};
|
|
12674
12304
|
const preset = doc.get("preset");
|
|
@@ -12850,7 +12480,7 @@ async function saveProjectAsTemplate(options) {
|
|
|
12850
12480
|
async function retokeniseManifest(manifestPath) {
|
|
12851
12481
|
let text;
|
|
12852
12482
|
try {
|
|
12853
|
-
text = await
|
|
12483
|
+
text = await readFile32(manifestPath, "utf8");
|
|
12854
12484
|
} catch {
|
|
12855
12485
|
return;
|
|
12856
12486
|
}
|
|
@@ -12871,7 +12501,7 @@ async function listCustomTemplates(templatesRoot) {
|
|
|
12871
12501
|
const dir = path22.join(templatesRoot, entry.name);
|
|
12872
12502
|
let label = prettify(entry.name);
|
|
12873
12503
|
try {
|
|
12874
|
-
const meta = JSON.parse(await
|
|
12504
|
+
const meta = JSON.parse(await readFile32(path22.join(dir, TEMPLATE_META_FILE), "utf8"));
|
|
12875
12505
|
if (typeof meta.label === "string" && meta.label)
|
|
12876
12506
|
label = meta.label;
|
|
12877
12507
|
} catch {}
|
|
@@ -12897,7 +12527,7 @@ async function importTemplateFromFolder(options) {
|
|
|
12897
12527
|
return saveProjectAsTemplate({ projectDir: sourceDir, name, templatesRoot });
|
|
12898
12528
|
}
|
|
12899
12529
|
// src/lib/snippets.ts
|
|
12900
|
-
import { readdir as readdir8, readFile as
|
|
12530
|
+
import { readdir as readdir8, readFile as readFile33, writeFile as writeFile12, mkdir as mkdir12, rm as rm4 } from "node:fs/promises";
|
|
12901
12531
|
import path23 from "node:path";
|
|
12902
12532
|
var SNIPPETS_DIR = "snippets";
|
|
12903
12533
|
var LEVEL_RANK = { project: 0, extension: 1, core: 2 };
|
|
@@ -12938,7 +12568,7 @@ async function scanSnippetFiles(dir) {
|
|
|
12938
12568
|
continue;
|
|
12939
12569
|
let body = "";
|
|
12940
12570
|
try {
|
|
12941
|
-
body = await
|
|
12571
|
+
body = await readFile33(path23.join(dir, fileName), "utf8");
|
|
12942
12572
|
} catch {
|
|
12943
12573
|
continue;
|
|
12944
12574
|
}
|
|
@@ -13024,7 +12654,7 @@ async function collectLibrary(projectDir) {
|
|
|
13024
12654
|
listed.component = name;
|
|
13025
12655
|
continue;
|
|
13026
12656
|
}
|
|
13027
|
-
const body = await
|
|
12657
|
+
const body = await readFile33(path23.join(entry.dir, rel), "utf8").catch(() => null);
|
|
13028
12658
|
if (body === null)
|
|
13029
12659
|
continue;
|
|
13030
12660
|
snippets2.push({
|
|
@@ -13074,7 +12704,7 @@ async function listMarkerComponents(projectDir) {
|
|
|
13074
12704
|
}
|
|
13075
12705
|
// src/lib/extension-import.ts
|
|
13076
12706
|
import { existsSync as existsSync16 } from "node:fs";
|
|
13077
|
-
import { cp as cp4, mkdir as mkdir13, mkdtemp as mkdtemp2, readFile as
|
|
12707
|
+
import { cp as cp4, mkdir as mkdir13, mkdtemp as mkdtemp2, readFile as readFile34, rm as rm5, writeFile as writeFile13 } from "node:fs/promises";
|
|
13078
12708
|
import { tmpdir as tmpdir2 } from "node:os";
|
|
13079
12709
|
import path24 from "node:path";
|
|
13080
12710
|
import { unzipSync } from "fflate";
|
|
@@ -13147,7 +12777,7 @@ async function finalizeExtensionImport(projectDir, sourceDir, relPaths, fallback
|
|
|
13147
12777
|
if (!existsSync16(cssPath)) {
|
|
13148
12778
|
throw new Error("A theme must contain a theme.css file.");
|
|
13149
12779
|
}
|
|
13150
|
-
const css = await
|
|
12780
|
+
const css = await readFile34(cssPath, "utf8");
|
|
13151
12781
|
const { reject, warnings: printFindings } = classifyThemeCssFindings(checkCss(css, "theme.css"));
|
|
13152
12782
|
if (reject) {
|
|
13153
12783
|
throw new Error(`theme.css could not be parsed — ${reject.message}`);
|
|
@@ -13175,7 +12805,7 @@ async function finalizeExtensionImport(projectDir, sourceDir, relPaths, fallback
|
|
|
13175
12805
|
for (let i = 0;i < extraSheets.length; i++) {
|
|
13176
12806
|
const rel = extraSheets[i];
|
|
13177
12807
|
const sheetPath = extraSheetPaths[i];
|
|
13178
|
-
const sheetCss = await
|
|
12808
|
+
const sheetCss = await readFile34(sheetPath, "utf8");
|
|
13179
12809
|
const { reject: sheetReject, warnings: sheetFindings } = classifyThemeCssFindings(checkCss(sheetCss, rel));
|
|
13180
12810
|
if (sheetReject) {
|
|
13181
12811
|
throw new Error(`${rel} could not be parsed — ${sheetReject.message}`);
|
|
@@ -13208,7 +12838,7 @@ async function completeLandedManifest(dest, id, meta, metaExists) {
|
|
|
13208
12838
|
let pkg = {};
|
|
13209
12839
|
if (metaExists) {
|
|
13210
12840
|
try {
|
|
13211
|
-
const parsed = JSON.parse(await
|
|
12841
|
+
const parsed = JSON.parse(await readFile34(file, "utf8"));
|
|
13212
12842
|
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
13213
12843
|
pkg = parsed;
|
|
13214
12844
|
}
|
|
@@ -13310,11 +12940,11 @@ async function importExtensionFromCssText(projectDir, css, name) {
|
|
|
13310
12940
|
async function importExtensionFromFile(projectDir, filePath) {
|
|
13311
12941
|
const ext = path24.extname(filePath).toLowerCase();
|
|
13312
12942
|
if (ext === ".zip") {
|
|
13313
|
-
const buf = await
|
|
12943
|
+
const buf = await readFile34(filePath);
|
|
13314
12944
|
return importExtensionFromZip(projectDir, new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength));
|
|
13315
12945
|
}
|
|
13316
12946
|
if (ext === ".css") {
|
|
13317
|
-
const css = await
|
|
12947
|
+
const css = await readFile34(filePath, "utf8");
|
|
13318
12948
|
return importExtensionFromCssText(projectDir, css, prettify(path24.basename(filePath, ".css")));
|
|
13319
12949
|
}
|
|
13320
12950
|
throw new Error("Choose a .zip extension package or a .css stylesheet.");
|
|
@@ -15885,7 +15515,7 @@ var drivethrurpgProvider = {
|
|
|
15885
15515
|
};
|
|
15886
15516
|
|
|
15887
15517
|
// src/lib/publish/providers/gdrive.ts
|
|
15888
|
-
import { mkdtemp as mkdtemp3, readFile as
|
|
15518
|
+
import { mkdtemp as mkdtemp3, readFile as readFile35, readdir as readdir11, rm as rm9, stat as stat9, writeFile as writeFile16 } from "node:fs/promises";
|
|
15889
15519
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
15890
15520
|
import path30 from "node:path";
|
|
15891
15521
|
import { Zip, ZipDeflate } from "fflate";
|
|
@@ -16277,12 +15907,12 @@ async function collectZipEntries(root, dir, out, onWarn) {
|
|
|
16277
15907
|
await collectZipEntries(root, full, out, onWarn);
|
|
16278
15908
|
} else if (entry.isFile()) {
|
|
16279
15909
|
const rel = path30.relative(root, full).split(path30.sep).join("/");
|
|
16280
|
-
out[rel] = await
|
|
15910
|
+
out[rel] = await readFile35(full);
|
|
16281
15911
|
} else if (entry.isSymbolicLink()) {
|
|
16282
15912
|
const resolved = await stat9(full).catch(() => null);
|
|
16283
15913
|
if (resolved?.isFile()) {
|
|
16284
15914
|
const rel = path30.relative(root, full).split(path30.sep).join("/");
|
|
16285
|
-
out[rel] = await
|
|
15915
|
+
out[rel] = await readFile35(full);
|
|
16286
15916
|
} else if (resolved?.isDirectory()) {
|
|
16287
15917
|
await collectZipEntries(root, full, out, onWarn);
|
|
16288
15918
|
} else {
|
|
@@ -17148,7 +16778,7 @@ async function disconnectPublishCredential(key, deps, options = {}) {
|
|
|
17148
16778
|
}
|
|
17149
16779
|
}
|
|
17150
16780
|
// src/lib/publish/selections.ts
|
|
17151
|
-
import { chmod as chmod3, mkdir as mkdir21, readFile as
|
|
16781
|
+
import { chmod as chmod3, mkdir as mkdir21, readFile as readFile36, writeFile as writeFile18 } from "node:fs/promises";
|
|
17152
16782
|
import path34 from "node:path";
|
|
17153
16783
|
class PublishSelectionsStore {
|
|
17154
16784
|
filePath;
|
|
@@ -17158,7 +16788,7 @@ class PublishSelectionsStore {
|
|
|
17158
16788
|
}
|
|
17159
16789
|
async read() {
|
|
17160
16790
|
try {
|
|
17161
|
-
const raw = await
|
|
16791
|
+
const raw = await readFile36(this.filePath, "utf8");
|
|
17162
16792
|
const parsed = JSON.parse(raw);
|
|
17163
16793
|
if (parsed && typeof parsed === "object") {
|
|
17164
16794
|
return {
|