gutterpress 0.11.16-alpha.6 → 0.11.17-alpha.1
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 -2
- package/dist/{build-bk0rw638.js → build-jfjzam95.js} +4 -4
- package/dist/{cli-n9e1mzb7.js → cli-0754wskb.js} +1 -1
- package/dist/{cli-ac7zs8sp.js → cli-ew3gc4nt.js} +166 -100
- package/dist/{cli-wqy8hnnh.js → cli-xx5bryh6.js} +7 -5
- package/dist/{cli-nzzsyw1e.js → cli-zce1zcqc.js} +1 -1
- package/dist/cli.js +12 -12
- package/dist/{doctor-qmd7gjwt.js → doctor-h01f71ws.js} +2 -2
- package/dist/engine/shared/synthesis.d.ts +8 -0
- package/dist/{engine-w17dbt4f.js → engine-aaam2nz3.js} +2 -2
- package/dist/{engine-j5h953pg.js → engine-rhmwgk9k.js} +1 -1
- package/dist/{ext-j28pn3ng.js → ext-ja4hy1c2.js} +4 -4
- package/dist/{gutterpress-viewer-swz6bwfa.js → gutterpress-viewer-5a6h4evk.js} +46 -5
- package/dist/{index-qep93v0z.js → index-3nk5mnn6.js} +7 -5
- package/dist/{index-ee7wp8q3.js → index-dmm31ys3.js} +1 -1
- package/dist/{index-ss8dv3zf.js → index-r9t4acx5.js} +165 -97
- package/dist/index.js +3 -3
- package/dist/lib/markdown/assemble.d.ts +10 -0
- package/dist/lib/markdown/gutterpress-css.d.ts +1 -1
- package/dist/lib/markdown/index.d.ts +10 -0
- package/dist/lib/static-serve.d.ts +6 -0
- package/dist/{new-rxkqh5t2.js → new-yzswp0ge.js} +4 -4
- package/dist/{preflight-wm3seg5z.js → preflight-0s1vw6y1.js} +4 -4
- package/dist/preview/file-watcher.d.ts +5 -1
- package/dist/preview/server-context.d.ts +10 -0
- package/dist/{preview-55jbgv9p.js → preview-tam7azsr.js} +4 -4
- package/dist/{publish-mv3kcwwn.js → publish-ra8kyf0z.js} +4 -4
- package/dist/render.js +30 -8
- package/dist/{validate-bhn2tjsw.js → validate-n9vae7p8.js} +4 -4
- package/package.json +1 -1
package/dist/api/index.js
CHANGED
|
@@ -131,10 +131,10 @@ import {
|
|
|
131
131
|
testRemoteAccess,
|
|
132
132
|
updateExtensions,
|
|
133
133
|
validateProjectExtensions
|
|
134
|
-
} from "../index-
|
|
134
|
+
} from "../index-r9t4acx5.js";
|
|
135
135
|
import {
|
|
136
136
|
BuildError
|
|
137
|
-
} from "../index-
|
|
137
|
+
} from "../index-dmm31ys3.js";
|
|
138
138
|
import {
|
|
139
139
|
DEFAULT_PRINT_OPTS,
|
|
140
140
|
assertMilestone,
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import {
|
|
2
2
|
runBuild,
|
|
3
3
|
splitOutPath
|
|
4
|
-
} from "./cli-
|
|
4
|
+
} from "./cli-ew3gc4nt.js";
|
|
5
5
|
import {
|
|
6
6
|
log
|
|
7
|
-
} from "./cli-
|
|
7
|
+
} from "./cli-0754wskb.js";
|
|
8
8
|
import {
|
|
9
9
|
UsageError,
|
|
10
10
|
parseFormat,
|
|
11
11
|
parsePdfxFlavor,
|
|
12
12
|
rejectExtraPositionals,
|
|
13
13
|
rejectUnknownFlags
|
|
14
|
-
} from "./cli-
|
|
15
|
-
import"./cli-
|
|
14
|
+
} from "./cli-zce1zcqc.js";
|
|
15
|
+
import"./cli-xx5bryh6.js";
|
|
16
16
|
import {
|
|
17
17
|
BuildError
|
|
18
18
|
} from "./cli-46ycxe6r.js";
|
|
@@ -13,17 +13,17 @@ import {
|
|
|
13
13
|
stampCreator,
|
|
14
14
|
stripAnnotations,
|
|
15
15
|
warn
|
|
16
|
-
} from "./cli-
|
|
16
|
+
} from "./cli-0754wskb.js";
|
|
17
17
|
import {
|
|
18
18
|
DEBOUNCE,
|
|
19
19
|
UsageError,
|
|
20
20
|
resolvePort
|
|
21
|
-
} from "./cli-
|
|
21
|
+
} from "./cli-zce1zcqc.js";
|
|
22
22
|
import {
|
|
23
23
|
MARGIN_BOX_IGNORED_PROPERTIES,
|
|
24
24
|
getAssetPath,
|
|
25
25
|
getAssetsDir
|
|
26
|
-
} from "./cli-
|
|
26
|
+
} from "./cli-xx5bryh6.js";
|
|
27
27
|
import {
|
|
28
28
|
BuildError,
|
|
29
29
|
EXIT_CODES
|
|
@@ -1181,16 +1181,23 @@ function resolveMarkerDeclaration(name, rawDecl, rawRegistry, originOf) {
|
|
|
1181
1181
|
}
|
|
1182
1182
|
return { name, baseKind: name, ...resolveContainerShape(name, pluginName, rawDecl) };
|
|
1183
1183
|
}
|
|
1184
|
+
var CORE_MARKER_OWNER = "Gutterpress";
|
|
1185
|
+
var CORE_DECLARED_MARKERS = {
|
|
1186
|
+
columns: {
|
|
1187
|
+
class: "gp-columns",
|
|
1188
|
+
variants: { 1: "gp-columns-1", 2: "gp-columns-2", 3: "gp-columns-3", 4: "gp-columns-4", 5: "gp-columns-5" }
|
|
1189
|
+
}
|
|
1190
|
+
};
|
|
1184
1191
|
function buildDeclaredMarkerRegistry(sources) {
|
|
1185
1192
|
const rawRegistry = new Map;
|
|
1186
1193
|
const originOf = new Map;
|
|
1187
|
-
for (const { pluginName, markers } of sources) {
|
|
1194
|
+
for (const { pluginName, markers } of [{ pluginName: CORE_MARKER_OWNER, markers: CORE_DECLARED_MARKERS }, ...sources]) {
|
|
1188
1195
|
if (!markers)
|
|
1189
1196
|
continue;
|
|
1190
1197
|
for (const [name, rawDecl] of Object.entries(markers)) {
|
|
1191
1198
|
validateDeclaredMarkerName(name, pluginName);
|
|
1192
|
-
if (KNOWN_KINDS.includes(name)) {
|
|
1193
|
-
throw new Error(`Plugin "${pluginName}" declares marker "@${name}", which is a core Gutterpress marker name ` + `(${KNOWN_KINDS.map((k) => `@${k}`).join(", ")}). Core marker names cannot be shadowed — ` + `rename the plugin's marker.`);
|
|
1199
|
+
if (KNOWN_KINDS.includes(name) || pluginName !== CORE_MARKER_OWNER && name in CORE_DECLARED_MARKERS) {
|
|
1200
|
+
throw new Error(`Plugin "${pluginName}" declares marker "@${name}", which is a core Gutterpress marker name ` + `(${[...KNOWN_KINDS, ...Object.keys(CORE_DECLARED_MARKERS)].map((k) => `@${k}`).join(", ")}). ` + `Core marker names cannot be shadowed — ` + `rename the plugin's marker.`);
|
|
1194
1201
|
}
|
|
1195
1202
|
if (rawRegistry.has(name)) {
|
|
1196
1203
|
throw new Error(`Marker "@${name}" is declared by both plugin "${originOf.get(name)}" and plugin "${pluginName}". ` + `Declared marker names must be unique across every loaded plugin — rename one of them.`);
|
|
@@ -1273,7 +1280,7 @@ function plugin(md, pluginOptions = {}) {
|
|
|
1273
1280
|
preferPagesInSpreads: false,
|
|
1274
1281
|
...pluginOptions
|
|
1275
1282
|
};
|
|
1276
|
-
const declaredMarkers = options.declaredMarkers instanceof Map && options.declaredMarkers.size > 0 ? options.declaredMarkers :
|
|
1283
|
+
const declaredMarkers = options.declaredMarkers instanceof Map && options.declaredMarkers.size > 0 ? options.declaredMarkers : buildDeclaredMarkerRegistry([]);
|
|
1277
1284
|
const declaredWords = declaredKindWords(declaredMarkers);
|
|
1278
1285
|
function markerBlock(state, startLine, endLine, silent) {
|
|
1279
1286
|
const pos = state.bMarks[startLine] + state.tShift[startLine];
|
|
@@ -1832,9 +1839,19 @@ var GUTTERPRESS_CSS = `
|
|
|
1832
1839
|
NOT set, because the correct value depends on whether the run fragments
|
|
1833
1840
|
across pages (auto packs each page's columns; the CSS initial balance is
|
|
1834
1841
|
right for a run that fits on one page) and only the author knows which.
|
|
1835
|
-
--gp-column-gap is author-settable.
|
|
1836
|
-
.gp-columns
|
|
1837
|
-
|
|
1842
|
+
--gp-column-gap is author-settable.
|
|
1843
|
+
.gp-columns is what the core @columns marker emits (markers.js); on its
|
|
1844
|
+
own it is two columns, and @columns 1 to 5 add the matching count, which
|
|
1845
|
+
wins because it comes later at the same specificity. */
|
|
1846
|
+
.gp-columns, .gp-columns-1, .gp-columns-2, .gp-columns-3, .gp-columns-4, .gp-columns-5 {
|
|
1847
|
+
column-gap: var(--gp-column-gap, 1.5em);
|
|
1848
|
+
}
|
|
1849
|
+
.gp-columns { columns: 2; }
|
|
1850
|
+
.gp-columns-1 { columns: 1; }
|
|
1851
|
+
.gp-columns-2 { columns: 2; }
|
|
1852
|
+
.gp-columns-3 { columns: 3; }
|
|
1853
|
+
.gp-columns-4 { columns: 4; }
|
|
1854
|
+
.gp-columns-5 { columns: 5; }
|
|
1838
1855
|
|
|
1839
1856
|
/* the per-shape decisions the paragraph above deliberately leaves to the
|
|
1840
1857
|
author, named instead of left as raw CSS every book was reinventing
|
|
@@ -2035,8 +2052,12 @@ var GP_CLASSES = new Set([
|
|
|
2035
2052
|
"gp-large",
|
|
2036
2053
|
"gp-tight",
|
|
2037
2054
|
"gp-loose",
|
|
2055
|
+
"gp-columns",
|
|
2056
|
+
"gp-columns-1",
|
|
2038
2057
|
"gp-columns-2",
|
|
2039
2058
|
"gp-columns-3",
|
|
2059
|
+
"gp-columns-4",
|
|
2060
|
+
"gp-columns-5",
|
|
2040
2061
|
"gp-columns-all",
|
|
2041
2062
|
"gp-columns-flow",
|
|
2042
2063
|
"gp-columns-balanced",
|
|
@@ -8312,8 +8333,9 @@ ${projectCss.trim()}` : null
|
|
|
8312
8333
|
`);
|
|
8313
8334
|
const preloadTags = (opts.preloadImages ?? []).map((href) => `
|
|
8314
8335
|
<link rel="preload" as="image" href="${href}">`).join("");
|
|
8336
|
+
const printAttrs = (opts.print?.signature && opts.print.signature > 1 ? ` data-gp-signature="${opts.print.signature}"` : "") + (opts.print?.reserveLastPage ? " data-gp-reserve-last-page" : "");
|
|
8315
8337
|
return `<!DOCTYPE html>
|
|
8316
|
-
<html lang="en">
|
|
8338
|
+
<html lang="en"${printAttrs}>
|
|
8317
8339
|
<head>
|
|
8318
8340
|
<meta charset="UTF-8">
|
|
8319
8341
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
@@ -8375,6 +8397,7 @@ ${css.trim()}
|
|
|
8375
8397
|
projectCss: inlined.css,
|
|
8376
8398
|
preloadImages: cssAssetCopies.map((c) => c.to),
|
|
8377
8399
|
title: opts.title,
|
|
8400
|
+
print: opts.print,
|
|
8378
8401
|
plugins: opts.plugins,
|
|
8379
8402
|
pluginCss,
|
|
8380
8403
|
annotateSourceChapters: opts.annotateSourceChapters,
|
|
@@ -8386,6 +8409,7 @@ async function renderChaptersToFile(inputDir, outDir, opts = {}) {
|
|
|
8386
8409
|
await mkdir4(outDir, { recursive: true });
|
|
8387
8410
|
const html = await renderChapters(inputDir, {
|
|
8388
8411
|
title: opts.title,
|
|
8412
|
+
print: opts.print,
|
|
8389
8413
|
styles: opts.styles,
|
|
8390
8414
|
files: opts.files,
|
|
8391
8415
|
plugins: opts.plugins,
|
|
@@ -9506,6 +9530,7 @@ async function renderBook(ctx) {
|
|
|
9506
9530
|
const cssAssets = [];
|
|
9507
9531
|
const htmlFile = await renderChaptersToFile(renderDir, workDir, {
|
|
9508
9532
|
title: config.title,
|
|
9533
|
+
print: config.print,
|
|
9509
9534
|
styles: config.styles,
|
|
9510
9535
|
files: config.source.files,
|
|
9511
9536
|
plugins,
|
|
@@ -9657,7 +9682,7 @@ class PdfOutput {
|
|
|
9657
9682
|
const rawPdf = pdfxMode ? path13.join(stage, "raw.pdf") : path13.resolve(pdfFile);
|
|
9658
9683
|
await fsp2.mkdir(path13.dirname(path13.resolve(pdfFile)), { recursive: true });
|
|
9659
9684
|
log.info("Rendering HTML to PDF via the Gutterpress engine (native Chromium pagination)");
|
|
9660
|
-
const { buildNativePdf } = await import("./engine-
|
|
9685
|
+
const { buildNativePdf } = await import("./engine-rhmwgk9k.js");
|
|
9661
9686
|
const engineDiagnostics = await buildNativePdf(htmlFile, rawPdf, {
|
|
9662
9687
|
title: config.title,
|
|
9663
9688
|
author: config.authors.length > 0 ? config.authors.join(", ") : undefined,
|
|
@@ -9788,7 +9813,7 @@ function openPath(filePath) {
|
|
|
9788
9813
|
}
|
|
9789
9814
|
|
|
9790
9815
|
// src/preview/lifecycle.ts
|
|
9791
|
-
import
|
|
9816
|
+
import path16 from "path";
|
|
9792
9817
|
import { tmpdir } from "os";
|
|
9793
9818
|
import { randomBytes as randomBytes2 } from "crypto";
|
|
9794
9819
|
import { readdir as readdir4, readFile as readFile24, writeFile as writeFile5 } from "node:fs/promises";
|
|
@@ -9813,7 +9838,65 @@ async function mkdir6(dirPath) {
|
|
|
9813
9838
|
// src/preview/file-watcher.ts
|
|
9814
9839
|
import { watch } from "chokidar";
|
|
9815
9840
|
import fsp3 from "node:fs/promises";
|
|
9816
|
-
import
|
|
9841
|
+
import path15 from "path";
|
|
9842
|
+
|
|
9843
|
+
// src/lib/static-serve.ts
|
|
9844
|
+
import path14 from "node:path";
|
|
9845
|
+
var STATIC_MIME = {
|
|
9846
|
+
".html": "text/html; charset=utf-8",
|
|
9847
|
+
".htm": "text/html; charset=utf-8",
|
|
9848
|
+
".css": "text/css",
|
|
9849
|
+
".js": "application/javascript",
|
|
9850
|
+
".mjs": "application/javascript",
|
|
9851
|
+
".json": "application/json",
|
|
9852
|
+
".png": "image/png",
|
|
9853
|
+
".jpg": "image/jpeg",
|
|
9854
|
+
".jpeg": "image/jpeg",
|
|
9855
|
+
".gif": "image/gif",
|
|
9856
|
+
".svg": "image/svg+xml",
|
|
9857
|
+
".webp": "image/webp",
|
|
9858
|
+
".avif": "image/avif",
|
|
9859
|
+
".ico": "image/x-icon",
|
|
9860
|
+
".woff": "font/woff",
|
|
9861
|
+
".woff2": "font/woff2",
|
|
9862
|
+
".ttf": "font/ttf",
|
|
9863
|
+
".otf": "font/otf"
|
|
9864
|
+
};
|
|
9865
|
+
function resolveWithinRoot(relPath, root) {
|
|
9866
|
+
const resolvedRoot = path14.resolve(root);
|
|
9867
|
+
const candidate = path14.resolve(resolvedRoot, "." + (relPath.startsWith("/") ? relPath : "/" + relPath));
|
|
9868
|
+
if (candidate !== resolvedRoot && !candidate.startsWith(resolvedRoot + path14.sep)) {
|
|
9869
|
+
return null;
|
|
9870
|
+
}
|
|
9871
|
+
return candidate;
|
|
9872
|
+
}
|
|
9873
|
+
function hasDotSegment(urlPathname) {
|
|
9874
|
+
let decoded;
|
|
9875
|
+
try {
|
|
9876
|
+
decoded = decodeURIComponent(urlPathname);
|
|
9877
|
+
} catch {
|
|
9878
|
+
return true;
|
|
9879
|
+
}
|
|
9880
|
+
return decoded.split(/[/\\]/).some((segment) => segment.startsWith("."));
|
|
9881
|
+
}
|
|
9882
|
+
function resolveStaticPath(urlPathname, root) {
|
|
9883
|
+
let decoded;
|
|
9884
|
+
try {
|
|
9885
|
+
decoded = decodeURIComponent(urlPathname);
|
|
9886
|
+
} catch {
|
|
9887
|
+
return null;
|
|
9888
|
+
}
|
|
9889
|
+
return resolveWithinRoot(decoded, root);
|
|
9890
|
+
}
|
|
9891
|
+
function imageRefKey(ref) {
|
|
9892
|
+
let key = ref.split(/[?#]/)[0].replace(/^\.\//, "").replace(/^\/+/, "");
|
|
9893
|
+
try {
|
|
9894
|
+
key = decodeURIComponent(key);
|
|
9895
|
+
} catch {}
|
|
9896
|
+
return key;
|
|
9897
|
+
}
|
|
9898
|
+
|
|
9899
|
+
// src/preview/file-watcher.ts
|
|
9817
9900
|
var EMPTY_BOOK_HTML = `<!doctype html>
|
|
9818
9901
|
<html lang="en">
|
|
9819
9902
|
<head>
|
|
@@ -9834,12 +9917,14 @@ async function renderPreviewBook(inputPath, config, opts) {
|
|
|
9834
9917
|
const { plugins, pluginStyles } = await loadPluginsWithCss(config.extensions, inputPath, (ref, err) => warn(`Skipping plugin "${ref}" in preview — ${err.message}`));
|
|
9835
9918
|
return renderChapters(inputPath, {
|
|
9836
9919
|
title: config.title ?? "Document",
|
|
9920
|
+
print: config.print,
|
|
9837
9921
|
styles: config.styles,
|
|
9838
9922
|
files: opts.files,
|
|
9839
9923
|
plugins,
|
|
9840
9924
|
pluginStyles,
|
|
9841
9925
|
annotateSourceChapters: true,
|
|
9842
9926
|
...opts.onCssAssets ? { onCssAssets: opts.onCssAssets } : {},
|
|
9927
|
+
...opts.onImageRefs ? { onImageRefs: opts.onImageRefs } : {},
|
|
9843
9928
|
onChapterWarnings: (file, warnings) => {
|
|
9844
9929
|
for (const w of warnings) {
|
|
9845
9930
|
warn(` ${file}, line ${w.line}: ${w.message}`);
|
|
@@ -9854,24 +9939,35 @@ function injectPreviewScripts(html) {
|
|
|
9854
9939
|
`;
|
|
9855
9940
|
return /<\/head>/i.test(html) ? html.replace(/<\/head>/i, scripts + "</head>") : html + scripts;
|
|
9856
9941
|
}
|
|
9857
|
-
async function generateAndWriteHtml(inputPath, tempDir, config, cssAssets) {
|
|
9942
|
+
async function generateAndWriteHtml(inputPath, tempDir, config, cssAssets, imageRefs) {
|
|
9858
9943
|
if (!inputPath) {
|
|
9859
9944
|
cssAssets.clear();
|
|
9860
|
-
|
|
9945
|
+
imageRefs?.clear();
|
|
9946
|
+
await fsp3.writeFile(path15.join(tempDir, BOOK_HTML_FILENAME), EMPTY_BOOK_HTML, "utf-8");
|
|
9861
9947
|
return;
|
|
9862
9948
|
}
|
|
9863
9949
|
const nextAssets = new Map;
|
|
9950
|
+
const nextImageRefs = new Set;
|
|
9864
9951
|
const html = await renderPreviewBook(inputPath, config, {
|
|
9865
9952
|
files: config.source?.files ?? null,
|
|
9866
9953
|
onCssAssets: (copies) => {
|
|
9867
9954
|
for (const copy of copies)
|
|
9868
9955
|
nextAssets.set(copy.to, copy.from);
|
|
9956
|
+
},
|
|
9957
|
+
onImageRefs: (refs) => {
|
|
9958
|
+
for (const ref of refs)
|
|
9959
|
+
nextImageRefs.add(imageRefKey(ref));
|
|
9869
9960
|
}
|
|
9870
9961
|
});
|
|
9871
9962
|
cssAssets.clear();
|
|
9872
9963
|
for (const [to, from] of nextAssets)
|
|
9873
9964
|
cssAssets.set(to, from);
|
|
9874
|
-
|
|
9965
|
+
if (imageRefs) {
|
|
9966
|
+
imageRefs.clear();
|
|
9967
|
+
for (const ref of nextImageRefs)
|
|
9968
|
+
imageRefs.add(ref);
|
|
9969
|
+
}
|
|
9970
|
+
await fsp3.writeFile(path15.join(tempDir, BOOK_HTML_FILENAME), injectPreviewScripts(html), "utf-8");
|
|
9875
9971
|
}
|
|
9876
9972
|
function isDotPathUnderRoot(candidatePath, root) {
|
|
9877
9973
|
const normalizedRoot = root.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
@@ -9908,23 +10004,23 @@ function isIgnoredWatchPath(candidatePath, projectRoot) {
|
|
|
9908
10004
|
return isDotPathUnderRoot(candidatePath, projectRoot) || isGeneratedProjectPath(relative2);
|
|
9909
10005
|
}
|
|
9910
10006
|
function isExternalWatchCandidate(candidatePath, targets) {
|
|
9911
|
-
const candidate =
|
|
10007
|
+
const candidate = path15.resolve(candidatePath);
|
|
9912
10008
|
for (const rawTarget of targets) {
|
|
9913
|
-
const target =
|
|
9914
|
-
const rel =
|
|
9915
|
-
if (rel === "" || rel !== ".." && !rel.startsWith(`..${
|
|
10009
|
+
const target = path15.resolve(rawTarget);
|
|
10010
|
+
const rel = path15.relative(candidate, target);
|
|
10011
|
+
if (rel === "" || rel !== ".." && !rel.startsWith(`..${path15.sep}`) && !path15.isAbsolute(rel))
|
|
9916
10012
|
return true;
|
|
9917
10013
|
}
|
|
9918
10014
|
return false;
|
|
9919
10015
|
}
|
|
9920
10016
|
async function nearestExistingDirectory(start) {
|
|
9921
|
-
let current =
|
|
10017
|
+
let current = path15.resolve(start);
|
|
9922
10018
|
while (true) {
|
|
9923
10019
|
try {
|
|
9924
10020
|
if ((await fsp3.stat(current)).isDirectory())
|
|
9925
10021
|
return current;
|
|
9926
10022
|
} catch {}
|
|
9927
|
-
const parent =
|
|
10023
|
+
const parent = path15.dirname(current);
|
|
9928
10024
|
if (parent === current)
|
|
9929
10025
|
return current;
|
|
9930
10026
|
current = parent;
|
|
@@ -9933,7 +10029,7 @@ async function nearestExistingDirectory(start) {
|
|
|
9933
10029
|
async function externalWatchRoots(targets) {
|
|
9934
10030
|
const roots = new Set;
|
|
9935
10031
|
for (const target of targets) {
|
|
9936
|
-
roots.add(await nearestExistingDirectory(
|
|
10032
|
+
roots.add(await nearestExistingDirectory(path15.dirname(path15.resolve(target))));
|
|
9937
10033
|
}
|
|
9938
10034
|
return [...roots];
|
|
9939
10035
|
}
|
|
@@ -9947,19 +10043,19 @@ async function extensionFolderFiles(dir) {
|
|
|
9947
10043
|
const meta = await readExtensionMeta(dir);
|
|
9948
10044
|
const entry = extensionEntry(meta);
|
|
9949
10045
|
return [
|
|
9950
|
-
|
|
9951
|
-
...entry ? [
|
|
10046
|
+
path15.join(dir, EXTENSION_MANIFEST_FILENAME),
|
|
10047
|
+
...entry ? [path15.resolve(dir, entry)] : [],
|
|
9952
10048
|
...await collectStyleDependencies(dir, extensionStyleList(meta))
|
|
9953
10049
|
];
|
|
9954
10050
|
}
|
|
9955
10051
|
async function externalWatchTargets(projectDir, config) {
|
|
9956
|
-
const root =
|
|
10052
|
+
const root = path15.resolve(projectDir);
|
|
9957
10053
|
let canonicalRoot = root;
|
|
9958
10054
|
try {
|
|
9959
10055
|
canonicalRoot = await fsp3.realpath(root);
|
|
9960
10056
|
} catch {}
|
|
9961
10057
|
const styles = await resolveActiveStyles(root, config.styles);
|
|
9962
|
-
const extensionPaths = (config.extensions ?? []).map((p) => p.path).filter((p) => !!p).map((p) =>
|
|
10058
|
+
const extensionPaths = (config.extensions ?? []).map((p) => p.path).filter((p) => !!p).map((p) => path15.resolve(root, p));
|
|
9963
10059
|
const candidates = [
|
|
9964
10060
|
...await collectStyleDependencies(root, styles),
|
|
9965
10061
|
...extensionPaths,
|
|
@@ -9967,17 +10063,17 @@ async function externalWatchTargets(projectDir, config) {
|
|
|
9967
10063
|
];
|
|
9968
10064
|
const external = new Set;
|
|
9969
10065
|
for (const abs of candidates) {
|
|
9970
|
-
const authoredPath =
|
|
9971
|
-
const authoredRel =
|
|
9972
|
-
if (authoredRel !== "" && (authoredRel === ".." || authoredRel.startsWith(`..${
|
|
10066
|
+
const authoredPath = path15.resolve(abs);
|
|
10067
|
+
const authoredRel = path15.relative(root, authoredPath);
|
|
10068
|
+
if (authoredRel !== "" && (authoredRel === ".." || authoredRel.startsWith(`..${path15.sep}`) || path15.isAbsolute(authoredRel))) {
|
|
9973
10069
|
external.add(authoredPath);
|
|
9974
10070
|
}
|
|
9975
10071
|
let canonicalPath = authoredPath;
|
|
9976
10072
|
try {
|
|
9977
10073
|
canonicalPath = await fsp3.realpath(canonicalPath);
|
|
9978
10074
|
} catch {}
|
|
9979
|
-
const rel =
|
|
9980
|
-
if (rel === "" || rel !== ".." && !rel.startsWith(`..${
|
|
10075
|
+
const rel = path15.relative(canonicalRoot, canonicalPath);
|
|
10076
|
+
if (rel === "" || rel !== ".." && !rel.startsWith(`..${path15.sep}`) && !path15.isAbsolute(rel))
|
|
9981
10077
|
continue;
|
|
9982
10078
|
external.add(canonicalPath);
|
|
9983
10079
|
}
|
|
@@ -10004,7 +10100,7 @@ async function addAndAwaitWatch(watcher, roots) {
|
|
|
10004
10100
|
}
|
|
10005
10101
|
}
|
|
10006
10102
|
function createFileWatcher(state) {
|
|
10007
|
-
const inputResolved =
|
|
10103
|
+
const inputResolved = path15.resolve(state.currentInputPath);
|
|
10008
10104
|
const watcher = watch(inputResolved, {
|
|
10009
10105
|
persistent: true,
|
|
10010
10106
|
ignoreInitial: true,
|
|
@@ -10044,7 +10140,7 @@ function createFileWatcher(state) {
|
|
|
10044
10140
|
async function recordChange(event, filePath) {
|
|
10045
10141
|
if (closed)
|
|
10046
10142
|
return;
|
|
10047
|
-
const target =
|
|
10143
|
+
const target = path15.resolve(filePath);
|
|
10048
10144
|
const settled = settledWrites.get(target);
|
|
10049
10145
|
if (settled && event !== "unlink" && Date.now() <= settled.expiresAt) {
|
|
10050
10146
|
const diskContent = await fsp3.readFile(target, "utf8").catch(() => null);
|
|
@@ -10065,7 +10161,7 @@ function createFileWatcher(state) {
|
|
|
10065
10161
|
recordChange(event, filePath);
|
|
10066
10162
|
});
|
|
10067
10163
|
externalWatcher.on("all", (event, filePath) => {
|
|
10068
|
-
const target =
|
|
10164
|
+
const target = path15.resolve(filePath);
|
|
10069
10165
|
if (!desiredExternals.has(target))
|
|
10070
10166
|
return;
|
|
10071
10167
|
if (event === "add" && suppressInitialExternalAdds.delete(target))
|
|
@@ -10073,8 +10169,8 @@ function createFileWatcher(state) {
|
|
|
10073
10169
|
recordChange(event, target);
|
|
10074
10170
|
});
|
|
10075
10171
|
function isWatchedSource(target) {
|
|
10076
|
-
const rel =
|
|
10077
|
-
const inProject = rel === "" || rel !== ".." && !rel.startsWith(`..${
|
|
10172
|
+
const rel = path15.relative(inputResolved, target);
|
|
10173
|
+
const inProject = rel === "" || rel !== ".." && !rel.startsWith(`..${path15.sep}`) && !path15.isAbsolute(rel);
|
|
10078
10174
|
if (inProject)
|
|
10079
10175
|
return !isIgnoredWatchPath(target, inputResolved);
|
|
10080
10176
|
return desiredExternals.has(target);
|
|
@@ -10099,7 +10195,7 @@ function createFileWatcher(state) {
|
|
|
10099
10195
|
state.notifySettledWrite = (filePath, writtenContent) => {
|
|
10100
10196
|
if (closed)
|
|
10101
10197
|
return;
|
|
10102
|
-
const target =
|
|
10198
|
+
const target = path15.resolve(filePath);
|
|
10103
10199
|
if (isWatchedSource(target)) {
|
|
10104
10200
|
acceptSettledWrite(target, writtenContent);
|
|
10105
10201
|
return;
|
|
@@ -10120,7 +10216,7 @@ function createFileWatcher(state) {
|
|
|
10120
10216
|
return;
|
|
10121
10217
|
let nextTargets;
|
|
10122
10218
|
try {
|
|
10123
|
-
nextTargets = new Set((await externalWatchTargets(inputResolved, state.config)).map((target) =>
|
|
10219
|
+
nextTargets = new Set((await externalWatchTargets(inputResolved, state.config)).map((target) => path15.resolve(target)));
|
|
10124
10220
|
} catch (err) {
|
|
10125
10221
|
debug(`Could not resolve external watch targets: ${err}`);
|
|
10126
10222
|
return;
|
|
@@ -10184,7 +10280,7 @@ function createFileWatcher(state) {
|
|
|
10184
10280
|
await syncExternalWatches();
|
|
10185
10281
|
if (closed)
|
|
10186
10282
|
return;
|
|
10187
|
-
await generateAndWriteHtml(inputResolved, state.tempDir, updatedConfig, state.cssAssets);
|
|
10283
|
+
await generateAndWriteHtml(inputResolved, state.tempDir, updatedConfig, state.cssAssets, state.imageRefs);
|
|
10188
10284
|
if (closed)
|
|
10189
10285
|
return;
|
|
10190
10286
|
state.previewServer?.broadcastReload();
|
|
@@ -10246,7 +10342,7 @@ async function stopFileWatcher(state) {
|
|
|
10246
10342
|
}
|
|
10247
10343
|
|
|
10248
10344
|
// src/preview/lifecycle.ts
|
|
10249
|
-
var TEMP_DIR_BASE =
|
|
10345
|
+
var TEMP_DIR_BASE = path16.join(tmpdir(), "gutterpress-preview");
|
|
10250
10346
|
var PID_FILE_NAME = ".gutterpress.pid";
|
|
10251
10347
|
function isProcessAlive(pid) {
|
|
10252
10348
|
if (!Number.isFinite(pid) || pid <= 0)
|
|
@@ -10266,8 +10362,8 @@ async function cleanupOrphanTempDirs() {
|
|
|
10266
10362
|
return;
|
|
10267
10363
|
}
|
|
10268
10364
|
for (const entry of entries) {
|
|
10269
|
-
const dir =
|
|
10270
|
-
const pidFile =
|
|
10365
|
+
const dir = path16.join(TEMP_DIR_BASE, entry);
|
|
10366
|
+
const pidFile = path16.join(dir, PID_FILE_NAME);
|
|
10271
10367
|
try {
|
|
10272
10368
|
const raw = await readFile24(pidFile, "utf8");
|
|
10273
10369
|
const pid = parseInt(raw.trim(), 10);
|
|
@@ -10281,10 +10377,10 @@ async function cleanupOrphanTempDirs() {
|
|
|
10281
10377
|
async function initializePreviewDirectories() {
|
|
10282
10378
|
await cleanupOrphanTempDirs();
|
|
10283
10379
|
const tempDirSuffix = randomBytes2(8).toString("hex");
|
|
10284
|
-
const tempDir =
|
|
10380
|
+
const tempDir = path16.join(TEMP_DIR_BASE, tempDirSuffix);
|
|
10285
10381
|
await mkdir6(tempDir);
|
|
10286
10382
|
debug(`Created temporary directory: ${tempDir}`);
|
|
10287
|
-
await writeFile5(
|
|
10383
|
+
await writeFile5(path16.join(tempDir, PID_FILE_NAME), `${process.pid}
|
|
10288
10384
|
`, "utf8");
|
|
10289
10385
|
return tempDir;
|
|
10290
10386
|
}
|
|
@@ -10307,7 +10403,7 @@ async function restartPreview(newInputPath, state) {
|
|
|
10307
10403
|
state.currentInputPath = newInputPath;
|
|
10308
10404
|
const manifest = await loadManifest(newInputPath);
|
|
10309
10405
|
state.config = resolveConfig({}, manifest);
|
|
10310
|
-
await generateAndWriteHtml(newInputPath, state.tempDir, state.config, state.cssAssets);
|
|
10406
|
+
await generateAndWriteHtml(newInputPath, state.tempDir, state.config, state.cssAssets, state.imageRefs);
|
|
10311
10407
|
startFileWatcher(state);
|
|
10312
10408
|
state.previewServer?.broadcastReload();
|
|
10313
10409
|
info("Preview restarted successfully");
|
|
@@ -10367,7 +10463,8 @@ function createServerState(inputPath, tempDir, config, options) {
|
|
|
10367
10463
|
tempDir,
|
|
10368
10464
|
config,
|
|
10369
10465
|
options,
|
|
10370
|
-
cssAssets: new Map
|
|
10466
|
+
cssAssets: new Map,
|
|
10467
|
+
imageRefs: new Set
|
|
10371
10468
|
};
|
|
10372
10469
|
}
|
|
10373
10470
|
|
|
@@ -10378,57 +10475,6 @@ import { createHash as createHash5, randomUUID as randomUUID3 } from "node:crypt
|
|
|
10378
10475
|
import { readFile as readFile25, stat as stat5 } from "node:fs/promises";
|
|
10379
10476
|
import path17 from "path";
|
|
10380
10477
|
import { WebSocket, WebSocketServer } from "ws";
|
|
10381
|
-
|
|
10382
|
-
// src/lib/static-serve.ts
|
|
10383
|
-
import path16 from "node:path";
|
|
10384
|
-
var STATIC_MIME = {
|
|
10385
|
-
".html": "text/html; charset=utf-8",
|
|
10386
|
-
".htm": "text/html; charset=utf-8",
|
|
10387
|
-
".css": "text/css",
|
|
10388
|
-
".js": "application/javascript",
|
|
10389
|
-
".mjs": "application/javascript",
|
|
10390
|
-
".json": "application/json",
|
|
10391
|
-
".png": "image/png",
|
|
10392
|
-
".jpg": "image/jpeg",
|
|
10393
|
-
".jpeg": "image/jpeg",
|
|
10394
|
-
".gif": "image/gif",
|
|
10395
|
-
".svg": "image/svg+xml",
|
|
10396
|
-
".webp": "image/webp",
|
|
10397
|
-
".avif": "image/avif",
|
|
10398
|
-
".ico": "image/x-icon",
|
|
10399
|
-
".woff": "font/woff",
|
|
10400
|
-
".woff2": "font/woff2",
|
|
10401
|
-
".ttf": "font/ttf",
|
|
10402
|
-
".otf": "font/otf"
|
|
10403
|
-
};
|
|
10404
|
-
function resolveWithinRoot(relPath, root) {
|
|
10405
|
-
const resolvedRoot = path16.resolve(root);
|
|
10406
|
-
const candidate = path16.resolve(resolvedRoot, "." + (relPath.startsWith("/") ? relPath : "/" + relPath));
|
|
10407
|
-
if (candidate !== resolvedRoot && !candidate.startsWith(resolvedRoot + path16.sep)) {
|
|
10408
|
-
return null;
|
|
10409
|
-
}
|
|
10410
|
-
return candidate;
|
|
10411
|
-
}
|
|
10412
|
-
function hasDotSegment(urlPathname) {
|
|
10413
|
-
let decoded;
|
|
10414
|
-
try {
|
|
10415
|
-
decoded = decodeURIComponent(urlPathname);
|
|
10416
|
-
} catch {
|
|
10417
|
-
return true;
|
|
10418
|
-
}
|
|
10419
|
-
return decoded.split(/[/\\]/).some((segment) => segment.startsWith("."));
|
|
10420
|
-
}
|
|
10421
|
-
function resolveStaticPath(urlPathname, root) {
|
|
10422
|
-
let decoded;
|
|
10423
|
-
try {
|
|
10424
|
-
decoded = decodeURIComponent(urlPathname);
|
|
10425
|
-
} catch {
|
|
10426
|
-
return null;
|
|
10427
|
-
}
|
|
10428
|
-
return resolveWithinRoot(decoded, root);
|
|
10429
|
-
}
|
|
10430
|
-
|
|
10431
|
-
// src/preview/http-server.ts
|
|
10432
10478
|
var HMR_PATH = "/__gutterpress-hmr";
|
|
10433
10479
|
function shellHtml(initialRevision, instanceId) {
|
|
10434
10480
|
return `<!doctype html>
|
|
@@ -10567,6 +10613,22 @@ async function serveRevalidatedStatic(req, absPath, res, validators) {
|
|
|
10567
10613
|
}
|
|
10568
10614
|
await serveStatic(absPath, res, PROJECT_ASSET_CACHE_CONTROL, { ETag: validator.etag });
|
|
10569
10615
|
}
|
|
10616
|
+
var missingImagePng;
|
|
10617
|
+
async function isMissingReferencedImage(pathname, absPath, refs) {
|
|
10618
|
+
if (!refs.has(imageRefKey(pathname)))
|
|
10619
|
+
return false;
|
|
10620
|
+
try {
|
|
10621
|
+
await stat5(absPath);
|
|
10622
|
+
return false;
|
|
10623
|
+
} catch (err) {
|
|
10624
|
+
return err?.code === "ENOENT";
|
|
10625
|
+
}
|
|
10626
|
+
}
|
|
10627
|
+
function serveMissingImage(res) {
|
|
10628
|
+
missingImagePng ??= Buffer.from(placeholderPng());
|
|
10629
|
+
res.writeHead(200, { "Content-Type": "image/png", "Cache-Control": "no-store" });
|
|
10630
|
+
res.end(missingImagePng);
|
|
10631
|
+
}
|
|
10570
10632
|
function matchesEmbedded(urlPathname) {
|
|
10571
10633
|
if (EMBEDDED_EXACT.has(urlPathname))
|
|
10572
10634
|
return true;
|
|
@@ -10718,6 +10780,10 @@ async function createPreviewServer(state, port) {
|
|
|
10718
10780
|
res.end("Not Found");
|
|
10719
10781
|
return;
|
|
10720
10782
|
}
|
|
10783
|
+
if (servingProjectRoot && await isMissingReferencedImage(pathname, absPath, state.imageRefs)) {
|
|
10784
|
+
serveMissingImage(res);
|
|
10785
|
+
return;
|
|
10786
|
+
}
|
|
10721
10787
|
const serve = servingProjectRoot ? serveRevalidatedStatic(req, absPath, res, projectAssetValidators) : serveStatic(absPath, res);
|
|
10722
10788
|
await serve.catch((err) => {
|
|
10723
10789
|
if (!res.headersSent) {
|
|
@@ -10793,7 +10859,7 @@ async function startPreviewServer(options) {
|
|
|
10793
10859
|
const config = await initializeConfiguration(inputPath);
|
|
10794
10860
|
const tempDir = await initializePreviewDirectories();
|
|
10795
10861
|
const state = createServerState(inputPath, tempDir, config, options);
|
|
10796
|
-
await generateAndWriteHtml(inputPath, tempDir, config, state.cssAssets);
|
|
10862
|
+
await generateAndWriteHtml(inputPath, tempDir, config, state.cssAssets, state.imageRefs);
|
|
10797
10863
|
const restartPreview2 = async (newInputPath) => {
|
|
10798
10864
|
await restartPreview(newInputPath, state);
|
|
10799
10865
|
};
|
|
@@ -681,6 +681,11 @@ function planRectoBlanks(sites) {
|
|
|
681
681
|
return wrong;
|
|
682
682
|
});
|
|
683
683
|
}
|
|
684
|
+
function signaturePadding(pageCount, signature = 1, reserveLastPage = false) {
|
|
685
|
+
const size = signature > 1 ? signature : 1;
|
|
686
|
+
const padded = (size - pageCount % size) % size;
|
|
687
|
+
return padded === 0 && reserveLastPage ? size : padded;
|
|
688
|
+
}
|
|
684
689
|
var WHICH_VALUES = new Set(["first", "start", "last", "first-except"]);
|
|
685
690
|
function parseWhich(raw) {
|
|
686
691
|
const w = (raw ?? "").trim();
|
|
@@ -1121,7 +1126,7 @@ var preview_shell_default = "./preview-shell-xwn84kqr.js";
|
|
|
1121
1126
|
var CGATS21_CRPC1_default = "./CGATS21_CRPC1-g0e3k7kr.icc";
|
|
1122
1127
|
|
|
1123
1128
|
// src/assets/engine/gutterpress-viewer.js
|
|
1124
|
-
var gutterpress_viewer_default = "./gutterpress-viewer-
|
|
1129
|
+
var gutterpress_viewer_default = "./gutterpress-viewer-5a6h4evk.js";
|
|
1125
1130
|
|
|
1126
1131
|
// src/assets/engine/gutterpress-agent.js
|
|
1127
1132
|
var gutterpress_agent_default = "./gutterpress-agent-cazqstr1.js";
|
|
@@ -1450,10 +1455,7 @@ async function postprocess(input, opts) {
|
|
|
1450
1455
|
g.media.width - inset,
|
|
1451
1456
|
g.media.height - inset
|
|
1452
1457
|
];
|
|
1453
|
-
const
|
|
1454
|
-
let padded = (signature - doc.getPageCount() % signature) % signature;
|
|
1455
|
-
if (padded === 0 && opts.reserveLastPage)
|
|
1456
|
-
padded = signature;
|
|
1458
|
+
const padded = signaturePadding(doc.getPageCount(), opts.signature, opts.reserveLastPage);
|
|
1457
1459
|
for (let i = 0;i < padded; i++)
|
|
1458
1460
|
doc.addPage([g.media.width, g.media.height]);
|
|
1459
1461
|
const wantMarks = opts.marks || g.marks.includes("crop") || g.marks.includes("cross");
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
// package.json
|
|
5
5
|
var package_default = {
|
|
6
6
|
name: "gutterpress",
|
|
7
|
-
version: "0.11.
|
|
7
|
+
version: "0.11.17-alpha.1",
|
|
8
8
|
description: "Markdown-to-PDF converter for professional print layout using a native Chromium print engine and Ghostscript.",
|
|
9
9
|
author: "itlackey",
|
|
10
10
|
license: "MPL-2.0",
|