gutterpress 0.11.23-alpha.1 → 0.11.23-alpha.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/README.md +27 -29
  2. package/dist/{README-8ef336pp.md → README-8db7btxb.md} +13 -19
  3. package/dist/api/index.d.ts +5 -5
  4. package/dist/api/index.js +16 -22
  5. package/dist/{build-09cd1n7s.js → build-m78jcpf7.js} +9 -10
  6. package/dist/{cli-5hkmp2wy.js → cli-1h17ktsg.js} +125 -187
  7. package/dist/{cli-nr6j6300.js → cli-5jzyw06s.js} +1 -1
  8. package/dist/{cli-habkc5ng.js → cli-a35w7wzg.js} +5 -4
  9. package/dist/{cli-dd115fa8.js → cli-h4x81x97.js} +152 -124
  10. package/dist/{cli-ccp7sxz3.js → cli-n2tsxqpn.js} +1 -1
  11. package/dist/{cli-b0vyjvmt.js → cli-s6djx4ma.js} +1 -1
  12. package/dist/{cli-h17e3mtz.js → cli-t8be9yeb.js} +380 -16
  13. package/dist/{cli-dtckwda1.js → cli-xsrffqzt.js} +192 -10
  14. package/dist/{index-r7jcsk6h.js → cli-y28j019d.js} +19 -10
  15. package/dist/cli.js +12 -12
  16. package/dist/{doctor-nddspx4n.js → doctor-j71jqce3.js} +3 -3
  17. package/dist/engine/shared/gcpm-extract.d.ts +8 -0
  18. package/dist/engine/shared/print-area.d.ts +16 -4
  19. package/dist/{engine-yjzknt0g.js → engine-1r6q80tq.js} +3 -3
  20. package/dist/{engine-892swzzc.js → engine-m4y10shc.js} +1 -2
  21. package/dist/{ext-zjpen4yx.js → ext-fq2hg9va.js} +18 -33
  22. package/dist/{extension-restore-jvs60x9b.js → extension-restore-9dh7c4tp.js} +4 -4
  23. package/dist/{extension-restore-w8xt4kbq.js → extension-restore-tmxtzkm0.js} +5 -6
  24. package/dist/{gutterpress-viewer-701vf4qp.js → gutterpress-viewer-mafsby5k.js} +9 -2
  25. package/dist/{index-2jpk25en.js → index-0wee4408.js} +380 -16
  26. package/dist/index-46ycxe6r.js +18 -0
  27. package/dist/{cli-h3phdstf.js → index-5x42amh8.js} +19 -10
  28. package/dist/{index-m4hhzg3c.js → index-7pck1q9c.js} +174 -142
  29. package/dist/{index-93pqkvty.js → index-h6yk5tjx.js} +5 -4
  30. package/dist/{index-apc8w9w8.js → index-nedd07bk.js} +187 -2
  31. package/dist/{index-0w2azsk1.js → index-nvmf22rt.js} +2 -4
  32. package/dist/{index-zrhyb967.js → index-prqvz3xm.js} +510 -587
  33. package/dist/index.js +17 -23
  34. package/dist/lib/extension-manager.d.ts +24 -50
  35. package/dist/lib/extension-manifest.d.ts +1 -13
  36. package/dist/lib/extension-scaffold.d.ts +3 -3
  37. package/dist/lib/extension-specifier.d.ts +23 -6
  38. package/dist/lib/manifest.d.ts +15 -1
  39. package/dist/lib/markdown/assemble.d.ts +4 -3
  40. package/dist/lib/markdown/math.d.ts +1 -1
  41. package/dist/lib/npm-plugin-installer.d.ts +1 -1
  42. package/dist/lib/page-size.d.ts +34 -27
  43. package/dist/lib/plugin-vendor.d.ts +11 -3
  44. package/dist/lib/printsafe.d.ts +1 -0
  45. package/dist/lib/project-gitignore.d.ts +2 -2
  46. package/dist/lib/project-scaffold.d.ts +5 -7
  47. package/dist/lib/project-templates.d.ts +9 -3
  48. package/dist/lib/snippets.d.ts +2 -1
  49. package/dist/lib/style-resolver.d.ts +1 -2
  50. package/dist/manifest-8afhrk30.yaml +19 -0
  51. package/dist/manifest-d4f9q79e.yaml +23 -0
  52. package/dist/manifest-gf13sjp8.yaml +27 -0
  53. package/dist/manifest-my7mdv8j.yaml +23 -0
  54. package/dist/{manifest.schema-9aeaered.json → manifest.schema-650pe0d1.json} +17 -5
  55. package/dist/{new-xhq8wczn.js → new-s4zcaepg.js} +22 -21
  56. package/dist/{package-aenwjew3.json → package-awwkt7sa.json} +0 -1
  57. package/dist/{page-rules-nsj3aw42.css → page-rules-fj09xct5.css} +12 -40
  58. package/dist/{plugin.test.js-xgxrd8hf.tpl → plugin.test.js-gxzqqfdh.tpl} +0 -1
  59. package/dist/{plugins-9en8m9y0.js → plugins-4vaf27n9.js} +4 -4
  60. package/dist/{plugins-gf0gkjmv.js → plugins-80emnf31.js} +2 -2
  61. package/dist/{preflight-negnxg7b.js → preflight-c7w1xdn3.js} +9 -10
  62. package/dist/{preview-cep2s9cg.js → preview-mzytcwyk.js} +9 -10
  63. package/dist/{publish-xery6qc6.js → publish-fez14ad4.js} +9 -10
  64. package/dist/render.js +24 -561
  65. package/dist/schema/manifest.types.d.ts +22 -0
  66. package/dist/{source-provider-qbfknhyy.js → source-provider-98k5deda.js} +2 -2
  67. package/dist/{source-provider-2r74a7wp.js → source-provider-knmcam50.js} +2 -2
  68. package/dist/{tokens-7984461t.css → tokens-ye64p899.css} +5 -12
  69. package/dist/{validate-3d0sgf4g.js → validate-p2chr6hr.js} +9 -10
  70. package/package.json +1 -1
  71. package/dist/cli-fe43evmf.js +0 -212
  72. package/dist/index-dsvk7q6s.js +0 -229
  73. package/dist/manifest-8f10dr4f.yaml +0 -17
  74. package/dist/manifest-n1gh3qw5.yaml +0 -9
  75. package/dist/package-97gm31sg.json +0 -10
  76. package/dist/package-gag6ykwn.json +0 -10
  77. package/dist/package-nrhkwf2m.json +0 -10
  78. package/dist/package-zttkgydq.json +0 -10
  79. package/dist/theme-9c58td2d.css +0 -76
  80. package/dist/theme-h5recz6c.css +0 -61
  81. package/dist/theme-j2bagrfx.css +0 -59
  82. package/dist/theme-nn6d53zy.css +0 -71
@@ -8,16 +8,16 @@ import {
8
8
  stampCreator,
9
9
  stripAnnotations,
10
10
  transparentPages
11
- } from "./cli-ccp7sxz3.js";
11
+ } from "./cli-n2tsxqpn.js";
12
12
  import {
13
13
  blackTextToGray
14
14
  } from "./cli-ht1bcqdd.js";
15
15
  import {
16
+ DEFAULT_PAGE_MARGIN_PT,
16
17
  MARGIN_BOX_IGNORED_PROPERTIES,
17
- extract,
18
- lastPageMode,
19
- resolvePage
20
- } from "./cli-dtckwda1.js";
18
+ getAssetPath,
19
+ lastPageMode
20
+ } from "./cli-xsrffqzt.js";
21
21
  import {
22
22
  countLinkAnnotations,
23
23
  getImageResolutions,
@@ -42,27 +42,31 @@ import {
42
42
  import {
43
43
  hasUncommittedChanges,
44
44
  listWorkdirChanges
45
- } from "./cli-habkc5ng.js";
45
+ } from "./cli-a35w7wzg.js";
46
46
  import {
47
47
  detectProjectSource,
48
48
  repoSubPath
49
49
  } from "./cli-v5mp7a6q.js";
50
50
  import {
51
- EXTENSIONS_DIR,
52
51
  FriendlyHttpError,
53
52
  MANIFEST_FILENAMES,
54
53
  PRESETS,
55
54
  PRESET_IDS,
56
55
  TARGETS,
57
56
  TARGET_IDS,
58
- addBuiltInStyleSet,
59
57
  addExtension,
60
58
  applyDefaultPdfStrictChecks,
59
+ cssLength,
61
60
  ensureProjectGitignore,
61
+ formatPageSize,
62
+ isPositivePoints,
63
+ judgeRect,
62
64
  loadManifest,
63
65
  loadManifestDoc,
64
66
  loadManifestWithPath,
65
67
  npmRegistryUrl,
68
+ pageBoxes,
69
+ printAreaMeta,
66
70
  publishTargetFor,
67
71
  resolveConfig,
68
72
  resolveConfigForTarget,
@@ -71,7 +75,7 @@ import {
71
75
  uniqueExtensionId,
72
76
  withFetchTimeout,
73
77
  writeManifestDoc
74
- } from "./cli-dd115fa8.js";
78
+ } from "./cli-h4x81x97.js";
75
79
  import {
76
80
  EXTENSION_MANIFEST_FILENAME,
77
81
  GUTTERPRESS_CSS,
@@ -92,7 +96,7 @@ import {
92
96
  readExtensionMeta,
93
97
  resolveDeclaredStyles,
94
98
  slugify
95
- } from "./cli-h17e3mtz.js";
99
+ } from "./cli-t8be9yeb.js";
96
100
  import {
97
101
  PACKAGE_META,
98
102
  PACKAGE_VERSION,
@@ -102,22 +106,20 @@ import {
102
106
  log,
103
107
  setLogLevel,
104
108
  warn
105
- } from "./cli-b0vyjvmt.js";
109
+ } from "./cli-s6djx4ma.js";
106
110
  import {
107
111
  DEBOUNCE,
108
112
  UsageError,
109
113
  resolvePort
110
114
  } from "./cli-d8xjns66.js";
111
- import {
112
- getAssetPath
113
- } from "./cli-fe43evmf.js";
114
115
  import {
115
116
  BuildError
116
117
  } from "./cli-46ycxe6r.js";
117
118
  import {
119
+ EXTENSIONS_DIR,
118
120
  resolveVendoredPluginInstallRoot,
119
121
  vendoredNpmPluginPackageDir
120
- } from "./cli-h3phdstf.js";
122
+ } from "./cli-y28j019d.js";
121
123
  import {
122
124
  __require
123
125
  } from "./cli-37x76zdn.js";
@@ -284,84 +286,6 @@ var check2 = {
284
286
  };
285
287
  registerCheck(check2);
286
288
 
287
- // src/engine/shared/print-area.ts
288
- function isPositivePoints(value) {
289
- return typeof value === "number" && Number.isFinite(value) && value > 0;
290
- }
291
- var round3 = (n) => Math.round(n * 1000) / 1000;
292
- function cssLength(pt) {
293
- const inches = round3(pt / 72);
294
- return Math.abs(inches * 72 - pt) < 0.000001 ? `${inches}in` : `${round3(pt)}pt`;
295
- }
296
- function formatPageSize(page) {
297
- return `${cssLength(page.width)} ${cssLength(page.height)}`;
298
- }
299
- function printAreaMeta(page) {
300
- const area = JSON.stringify({
301
- width: page.width,
302
- height: page.height,
303
- bleed: page.bleed ?? 0,
304
- safe: page.safe ?? 0,
305
- artSafe: page.artSafe,
306
- gutter: page.gutter,
307
- preset: page.preset,
308
- spec: page.spec
309
- });
310
- return `<meta name="gp-print-area" content='${area.replace(/&/g, "&amp;").replace(/'/g, "&#39;")}'>`;
311
- }
312
- function pageBoxes(area, side, scale = 1) {
313
- const w = area.width * scale;
314
- const h = area.height * scale;
315
- const b = Math.max(0, area.bleed) * scale;
316
- const s = Math.max(0, area.safe) * scale;
317
- const a = Math.max(0, area.artSafe) * scale;
318
- const g = Math.max(0, area.gutter) * scale;
319
- const [textLeft, textRight] = side === "verso" ? [s, g] : [g, s];
320
- const [artLeft, artRight] = side === "verso" ? [a, g] : [g, a];
321
- const trim = { x: side === "verso" ? b : 0, y: b, w: Math.max(0, w - b), h: Math.max(0, h - 2 * b) };
322
- return {
323
- sheet: { x: 0, y: 0, w, h },
324
- trim,
325
- safe: {
326
- x: trim.x + textLeft,
327
- y: trim.y + s,
328
- w: Math.max(0, trim.w - textLeft - textRight),
329
- h: Math.max(0, trim.h - 2 * s)
330
- },
331
- safeArt: {
332
- x: trim.x + artLeft,
333
- y: trim.y + a,
334
- w: Math.max(0, trim.w - artLeft - artRight),
335
- h: Math.max(0, trim.h - 2 * a)
336
- },
337
- bleed: b
338
- };
339
- }
340
- var SEVERITY = { inside: 0, unsafe: 1, bleed: 2, "off-page": 3 };
341
- function judgeRect(r, boxes, rule, tol = 0) {
342
- const { sheet, trim } = boxes;
343
- const safe = rule === "art" ? boxes.safeArt : boxes.safe;
344
- const sides = [
345
- ["left", -r.x, -safe.x, -trim.x, -sheet.x],
346
- ["right", r.x + r.w, safe.x + safe.w, trim.x + trim.w, sheet.x + sheet.w],
347
- ["top", -r.y, -safe.y, -trim.y, -sheet.y],
348
- ["bottom", r.y + r.h, safe.y + safe.h, trim.y + trim.h, sheet.y + sheet.h]
349
- ];
350
- let worst = { kind: "inside", gap: 0, need: 0, edge: null };
351
- let beyond = 0;
352
- for (const [edge, ink, limit, trimEdge, sheetEdge] of sides) {
353
- const past = ink - limit;
354
- if (past <= tol || rule === "art" && ink >= sheetEdge - tol)
355
- continue;
356
- const kind = ink > sheetEdge + tol ? "off-page" : ink > trimEdge + tol ? "bleed" : "unsafe";
357
- if (SEVERITY[kind] > SEVERITY[worst.kind] || kind === worst.kind && past > beyond) {
358
- worst = { kind, gap: trimEdge - ink, need: trimEdge - limit, edge };
359
- beyond = past;
360
- }
361
- }
362
- return worst;
363
- }
364
-
365
289
  // src/checks/pdf/safe-margins.ts
366
290
  var TOLERANCE_PT = 0.5;
367
291
  var ABOVE_BASELINE = 0.8;
@@ -1391,6 +1315,7 @@ var ruleRiskyProps = "printsafe/no-risky-print-effects";
1391
1315
  var ruleSyntax = "printsafe/syntax-error";
1392
1316
  var rulePageContainment = "printsafe/page-containment";
1393
1317
  var rulePreviewCannotFollow = "printsafe/preview-cannot-follow";
1318
+ var rulePageSizeInStylesheet = "printsafe/page-size-in-stylesheet";
1394
1319
  function extractUrls(value) {
1395
1320
  const urls = [];
1396
1321
  const re = /url\(\s*(['"]?)(.*?)\1\s*\)/gi;
@@ -1439,6 +1364,12 @@ function isInPageBox(decl) {
1439
1364
  const page = decl.parent;
1440
1365
  return !!page && page.type === "atrule" && page.name.toLowerCase() === "page";
1441
1366
  }
1367
+ function isInBookPageRule(decl) {
1368
+ if (!isInPageBox(decl))
1369
+ return false;
1370
+ const params = decl.parent.params.trim();
1371
+ return params === "" || /^(:[a-z-]+\s*)+$/i.test(params);
1372
+ }
1442
1373
  function isDroppedPageGradient(decl) {
1443
1374
  const prop = decl.prop.toLowerCase();
1444
1375
  if (prop !== "background" && prop !== "background-image")
@@ -1678,6 +1609,15 @@ function checkCssRaw(css, from) {
1678
1609
  root.walkAtRules((at) => reportRemoteUrls(at.params || "", at));
1679
1610
  root.walkDecls((decl) => {
1680
1611
  const prop = decl.prop.toLowerCase();
1612
+ if (prop === "size" && isInBookPageRule(decl)) {
1613
+ warnings.push({
1614
+ rule: rulePageSizeInStylesheet,
1615
+ severity: "warning",
1616
+ message: `"size" in a stylesheet's @page rule is ignored: the page size comes from the manifest (preset:, or page: width and height — Setup > Details in the app), which is written after every stylesheet. Remove this declaration; to print at another size, change the manifest.`,
1617
+ ...nodeLoc(decl)
1618
+ });
1619
+ return;
1620
+ }
1681
1621
  if (isInertValue(prop, decl.value))
1682
1622
  return;
1683
1623
  if (marginBoxIgnoredProperties.has(prop) && isInPageMarginBox(decl)) {
@@ -1818,13 +1758,7 @@ import { existsSync as existsSync3 } from "node:fs";
1818
1758
  import { readdir } from "node:fs/promises";
1819
1759
  import path from "node:path";
1820
1760
  var STYLES_SUBDIR = "styles";
1821
- var FALLBACK_PRIORITY = [
1822
- "styles/book.css",
1823
- "css/print.css",
1824
- "css/index.css",
1825
- "css/style.css",
1826
- "css/main.css"
1827
- ];
1761
+ var DEFAULT_STYLESHEET = "styles/book.css";
1828
1762
  function relDisplay(projectDir, absPath) {
1829
1763
  return path.relative(projectDir, absPath).split(path.sep).join("/");
1830
1764
  }
@@ -1862,10 +1796,8 @@ async function resolveActiveStyles(projectDir, manifestStyles) {
1862
1796
  const manifest = configured.filter((s) => typeof s === "string" && s.trim().length > 0);
1863
1797
  if (manifest.length > 0)
1864
1798
  return manifest;
1865
- for (const rel of FALLBACK_PRIORITY) {
1866
- if (existsSync3(path.join(projectDir, rel)))
1867
- return [rel];
1868
- }
1799
+ if (existsSync3(path.join(projectDir, DEFAULT_STYLESHEET)))
1800
+ return [DEFAULT_STYLESHEET];
1869
1801
  const discovered = await discoverCssFiles(projectDir);
1870
1802
  if (discovered.length > 0) {
1871
1803
  const first = discovered.map((abs) => relDisplay(projectDir, abs)).sort((a, b) => a.localeCompare(b))[0];
@@ -4006,16 +3938,25 @@ function canonicalChapterId(p) {
4006
3938
  }
4007
3939
 
4008
3940
  // src/lib/markdown/assemble.ts
4009
- function defaultPageSizeCss(css, page) {
3941
+ function pageGeometryCss(page) {
4010
3942
  if (!page || !isPositivePoints(page.width) || !isPositivePoints(page.height))
4011
3943
  return null;
4012
- try {
4013
- if (resolvePage(extract(css)).decls.size !== undefined)
4014
- return null;
4015
- } catch {
3944
+ const size2 = `size: ${formatPageSize(page)};`;
3945
+ const m = page.margin;
3946
+ if (!m)
3947
+ return `@page { ${size2} }`;
3948
+ const [top, bottom, inside, outside] = [m.top, m.bottom, m.inside, m.outside].map(cssLength);
3949
+ const recto = `margin: ${top} ${outside} ${bottom} ${inside};`;
3950
+ const verso = `margin: ${top} ${inside} ${bottom} ${outside};`;
3951
+ return [`@page { ${size2} ${recto} }`, `@page :left { ${verso} }`, `@page :right { ${recto} }`].join(`
3952
+ `);
3953
+ }
3954
+ function defaultPageMarginCss(page) {
3955
+ if (!page || page.margin)
4016
3956
  return null;
4017
- }
4018
- return `@page { size: ${formatPageSize(page)}; }`;
3957
+ return `@layer gp.vocab {
3958
+ @page { margin: ${cssLength(DEFAULT_PAGE_MARGIN_PT)}; }
3959
+ }`;
4019
3960
  }
4020
3961
  async function assembleBookHtml(opts) {
4021
3962
  const title = opts.title ?? "Document";
@@ -4055,8 +3996,8 @@ async function assembleBookHtml(opts) {
4055
3996
  imageRefs.add(ref);
4056
3997
  opts.onImageRefs([...imageRefs]);
4057
3998
  }
4058
- const pageSize = defaultPageSizeCss(`${pluginCss}
4059
- ${projectCss}`, opts.printArea);
3999
+ const pageGeometry = pageGeometryCss(opts.printArea);
4000
+ const defaultMargin = defaultPageMarginCss(opts.printArea);
4060
4001
  const inlineCss = [
4061
4002
  "@layer gp.marker, gp.vocab;",
4062
4003
  `/* gutterpress markers */
@@ -4068,14 +4009,16 @@ ${TWO_VERSIONS_CSS.trim()}
4068
4009
  @layer gp.vocab {
4069
4010
  ${GUTTERPRESS_CSS.trim()}
4070
4011
  }`,
4071
- pageSize ? `/* page size (manifest) */
4072
- ${pageSize}` : null,
4012
+ defaultMargin ? `/* page margins (default) */
4013
+ ${defaultMargin}` : null,
4073
4014
  pluginCss ? `/* extension css */
4074
4015
  ${pluginCss.trim()}` : null,
4075
4016
  `/* column alignment */
4076
4017
  ${TABLE_ALIGN_CSS.trim()}`,
4077
4018
  projectCss ? `/* project css */
4078
- ${projectCss.trim()}` : null
4019
+ ${projectCss.trim()}` : null,
4020
+ pageGeometry ? `/* page geometry (manifest) */
4021
+ ${pageGeometry}` : null
4079
4022
  ].filter(Boolean).join(`
4080
4023
 
4081
4024
  `);
@@ -5217,7 +5160,7 @@ class PdfOutput {
5217
5160
  const rawPdf = pdfxMode ? path7.join(stage, "raw.pdf") : path7.resolve(pdfFile);
5218
5161
  await fsp2.mkdir(path7.dirname(path7.resolve(pdfFile)), { recursive: true });
5219
5162
  log.info("Rendering HTML to PDF via the Gutterpress engine (native Chromium pagination)");
5220
- const { buildNativePdf } = await import("./engine-892swzzc.js");
5163
+ const { buildNativePdf } = await import("./engine-m4y10shc.js");
5221
5164
  const engineDiagnostics = await buildNativePdf(htmlFile, rawPdf, {
5222
5165
  title: config.title,
5223
5166
  author: config.authors.length > 0 ? config.authors.join(", ") : undefined,
@@ -5597,7 +5540,7 @@ function isGeneratedProjectPath(relative) {
5597
5540
  const segment = segments[i];
5598
5541
  if (segment === "dist" || segment === "node_modules")
5599
5542
  return true;
5600
- if (segment === "plugins" && segments[i + 1] === "npm")
5543
+ if ((segment === "extensions" || segment === "plugins") && segments[i + 1] === "npm")
5601
5544
  return true;
5602
5545
  }
5603
5546
  return false;
@@ -6506,60 +6449,36 @@ async function startPreviewServer(options) {
6506
6449
  };
6507
6450
  }
6508
6451
 
6509
- // src/lib/project-templates.ts
6510
- import { isMap, isScalar, isSeq, parseDocument } from "yaml";
6511
- var BUILT_IN_TEMPLATE_IDS = [
6512
- "book",
6513
- "zine",
6514
- "technical",
6515
- "paper"
6516
- ];
6517
- var BUILT_IN_META = {
6518
- book: {
6519
- label: "Book",
6520
- description: "A clean starting point for a novel, memoir, or any long-form book."
6521
- },
6522
- zine: {
6523
- label: "Zine",
6524
- description: "A short, personal zine made to be printed, folded, and shared."
6525
- },
6526
- technical: {
6527
- label: "Technical document",
6528
- description: "A manual or guide with steps, reference tables, and code examples."
6529
- },
6530
- paper: {
6531
- label: "Academic paper",
6532
- description: "A journal-style article with LaTeX math, numbered equations, figures, tables, notes and references.",
6533
- look: "academic"
6534
- }
6535
- };
6536
- var SKIP_ENTRIES = new Set([
6537
- ".git",
6538
- "node_modules",
6539
- "out",
6540
- "dist",
6541
- "build",
6542
- ".gutterpress",
6543
- ".DS_Store"
6544
- ]);
6545
-
6546
6452
  // src/lib/project-scaffold.ts
6547
6453
  import { access, copyFile, cp, mkdir as mkdir4, readdir as readdir5, readFile as readFile22, stat as stat4, writeFile as writeFile5 } from "node:fs/promises";
6548
6454
  import { constants as FS, existsSync as existsSync7 } from "node:fs";
6549
6455
  import path12 from "node:path";
6550
6456
 
6551
6457
  // src/lib/page-size.ts
6552
- import postcss5 from "postcss";
6553
- import { isMap as isMap2, Scalar } from "yaml";
6458
+ import { isMap } from "yaml";
6554
6459
  function writePageBounds(doc, page) {
6555
6460
  const tolerance = page.tolerance ?? numberAt(doc, ["page", "tolerance"]);
6556
- if (!isMap2(doc.get("page", true)))
6557
- doc.set("page", doc.createNode({}));
6461
+ ensurePageMap(doc);
6558
6462
  doc.setIn(["page", "width"], page.width);
6559
6463
  doc.setIn(["page", "height"], page.height);
6560
6464
  if (tolerance !== undefined)
6561
6465
  doc.setIn(["page", "tolerance"], tolerance);
6562
6466
  }
6467
+ function deletePageBounds(doc) {
6468
+ const block = doc.get("page", true);
6469
+ if (!isMap(block)) {
6470
+ doc.delete("page");
6471
+ return;
6472
+ }
6473
+ for (const key of ["width", "height", "tolerance"])
6474
+ block.delete(key);
6475
+ if (block.items.length === 0)
6476
+ doc.delete("page");
6477
+ }
6478
+ function ensurePageMap(doc) {
6479
+ if (!isMap(doc.get("page", true)))
6480
+ doc.set("page", doc.createNode({}));
6481
+ }
6563
6482
  function numberAt(doc, keyPath) {
6564
6483
  const v = doc.getIn(keyPath);
6565
6484
  return isPositivePoints(v) ? v : undefined;
@@ -6568,14 +6487,15 @@ function numberAt(doc, keyPath) {
6568
6487
  // src/lib/project-scaffold.ts
6569
6488
  function starterOverridesCss() {
6570
6489
  return `/**
6571
- * Your book's own styles.
6490
+ * Your book's own styles. Rules here win over your look's.
6572
6491
  *
6573
- * This file loads AFTER every extension, so any rule you add here overrides
6574
- * a look's defaults. A new book has no look until you add one (the paper
6575
- * template adds the academic look for you):
6576
- * gutterpress ext add clean-book <book> --look (a built-in look)
6577
- * gutterpress ext add <package> <book> (a look from npm)
6578
- * A book has one look at a time; adding another turns the current one off.
6492
+ * In the app you rarely need this file: Setup > Looks & features adds a
6493
+ * look, Setup > Design changes its fonts, colors and sizes (those changes
6494
+ * are saved here as :root custom properties), and Setup > Details sets the
6495
+ * page size and margins (in the manifest).
6496
+ *
6497
+ * To change the look from the command line: gutterpress ext remove <old>
6498
+ * <book>, then gutterpress ext add <look> <book>.
6579
6499
  */
6580
6500
  `;
6581
6501
  }
@@ -6596,9 +6516,8 @@ function escapeYamlScalar(value) {
6596
6516
  }
6597
6517
  var DEFAULT_AUTHOR = "Anonymous";
6598
6518
  function requirePreset(preset, customPage) {
6599
- if (!preset || !PRESET_IDS.includes(preset)) {
6600
- const got = preset ? ` (got "${preset}")` : "";
6601
- throw new CreateProjectErrorImpl("preset-required", `A preset is required to create a book${got}. Choose one of: ${PRESET_IDS.join(", ")}.`);
6519
+ if (!PRESET_IDS.includes(preset)) {
6520
+ throw new CreateProjectErrorImpl("preset-required", `Unknown preset "${preset}". Choose one of: ${PRESET_IDS.join(", ")}.`);
6602
6521
  }
6603
6522
  if (preset === "custom") {
6604
6523
  const missing = [];
@@ -6656,7 +6575,7 @@ async function scaffoldProject(options) {
6656
6575
  }
6657
6576
  const template = options.template ?? "book";
6658
6577
  const customTemplateDir = options.templateDir;
6659
- const preset = customTemplateDir && options.preset === undefined ? undefined : requirePreset(options.preset, options.customPage);
6578
+ const preset = options.preset === undefined ? undefined : requirePreset(options.preset, options.customPage);
6660
6579
  const targets = preset ? resolveScaffoldTargets(options.targets, preset) : undefined;
6661
6580
  try {
6662
6581
  await mkdir4(projectDir, { recursive: true });
@@ -6694,13 +6613,14 @@ async function scaffoldProject(options) {
6694
6613
  let openFile = path12.join(projectDir, "chapter-01.md");
6695
6614
  try {
6696
6615
  await fillTemplateFile(manifestPath, substitutions);
6697
- const look = customTemplateDir ? undefined : BUILT_IN_META[template].look;
6698
- if (look)
6699
- await addBuiltInStyleSet(projectDir, look);
6700
- if (preset) {
6616
+ if (preset || options.customPage) {
6701
6617
  const { doc, file } = await loadManifestDoc(projectDir);
6702
- doc.set("preset", preset);
6703
- doc.set("targets", doc.createNode(targets ?? []));
6618
+ if (preset) {
6619
+ doc.set("preset", preset);
6620
+ doc.set("targets", doc.createNode(targets ?? []));
6621
+ if (preset !== "custom")
6622
+ deletePageBounds(doc);
6623
+ }
6704
6624
  if (options.customPage)
6705
6625
  writePageBounds(doc, options.customPage);
6706
6626
  await writeManifestDoc(file, doc);
@@ -6717,7 +6637,7 @@ async function scaffoldProject(options) {
6717
6637
  let versionHistoryError;
6718
6638
  if (requested === "local-git") {
6719
6639
  try {
6720
- const { providerFor } = await import("./source-provider-2r74a7wp.js");
6640
+ const { providerFor } = await import("./source-provider-knmcam50.js");
6721
6641
  const provider = providerFor({ type: "local-folder", path: projectDir });
6722
6642
  await provider.initVersionHistory({
6723
6643
  projectDir,
@@ -6769,7 +6689,7 @@ async function fillTemplateFile(filePath, substitutions) {
6769
6689
  import { access as access2, mkdir as mkdir5, readFile as readFile23, writeFile as writeFile6 } from "node:fs/promises";
6770
6690
  import { constants as FS2 } from "node:fs";
6771
6691
  import path13 from "node:path";
6772
- var EXTENSION_KINDS = ["plugin", "theme"];
6692
+ var EXTENSION_KINDS = ["plugin", "look"];
6773
6693
  var RESERVED_PREFIX = "gp-";
6774
6694
  var TEMPLATE_FILES = {
6775
6695
  plugin: [
@@ -6782,7 +6702,7 @@ var TEMPLATE_FILES = {
6782
6702
  ["test/expected.html", "test/expected.html"],
6783
6703
  ["test/plugin.test.js.tpl", "test/plugin.test.js"]
6784
6704
  ],
6785
- theme: [
6705
+ look: [
6786
6706
  ["package.json", "package.json"],
6787
6707
  ["README.md", "README.md"],
6788
6708
  ["components.yaml", "components.yaml"],
@@ -6797,11 +6717,11 @@ var TEMPLATE_FILES = {
6797
6717
  };
6798
6718
  var OPEN_FILE = {
6799
6719
  plugin: "plugin.js",
6800
- theme: "styles/tokens.css"
6720
+ look: "styles/tokens.css"
6801
6721
  };
6802
6722
  var DEFAULT_DESCRIPTION = {
6803
6723
  plugin: "A Gutterpress plugin.",
6804
- theme: "A Gutterpress theme."
6724
+ look: "A Gutterpress look."
6805
6725
  };
6806
6726
  var DEFAULT_AUTHOR2 = "Anonymous";
6807
6727
 
@@ -6833,7 +6753,7 @@ function escapeJsonScalar(value) {
6833
6753
  }
6834
6754
  async function scaffoldExtension(options) {
6835
6755
  const kind = options.kind;
6836
- if (kind !== "plugin" && kind !== "theme") {
6756
+ if (kind !== "plugin" && kind !== "look") {
6837
6757
  throw new ExtensionScaffoldError("invalid-name", `Unknown extension kind "${String(kind)}". Choose one of: ${EXTENSION_KINDS.join(", ")}.`);
6838
6758
  }
6839
6759
  const name = (options.name ?? "").trim();
@@ -6909,6 +6829,24 @@ function substitute(text, table) {
6909
6829
  return out;
6910
6830
  }
6911
6831
 
6832
+ // src/lib/project-templates.ts
6833
+ import { isMap as isMap2, isScalar, isSeq, parseDocument } from "yaml";
6834
+ var BUILT_IN_TEMPLATE_IDS = [
6835
+ "book",
6836
+ "zine",
6837
+ "technical",
6838
+ "paper"
6839
+ ];
6840
+ var SKIP_ENTRIES = new Set([
6841
+ ".git",
6842
+ "node_modules",
6843
+ "out",
6844
+ "dist",
6845
+ "build",
6846
+ ".gutterpress",
6847
+ ".DS_Store"
6848
+ ]);
6849
+
6912
6850
  // src/lib/extension-import.ts
6913
6851
  import { existsSync as existsSync8 } from "node:fs";
6914
6852
  import { cp as cp2, mkdir as mkdir6, mkdtemp, readFile as readFile24, rm, writeFile as writeFile7 } from "node:fs/promises";
@@ -9053,7 +8991,7 @@ async function resolvePublishProvider(id, book) {
9053
8991
  const ext = await bookExtensions(book);
9054
8992
  const npmEntry = ext.extensions.some((c) => !c.path && c.name === id);
9055
8993
  if (npmEntry) {
9056
- const { restoreForCommand: restoreForCommand2 } = await import("./extension-restore-w8xt4kbq.js");
8994
+ const { restoreForCommand: restoreForCommand2 } = await import("./extension-restore-tmxtzkm0.js");
9057
8995
  await restoreForCommand2(book.projectDir, { manifestPath: book.manifestPath, failFast: true });
9058
8996
  }
9059
8997
  const publishers = await discover(ext);
@@ -9091,7 +9029,7 @@ function infoFor(p) {
9091
9029
  }
9092
9030
  function pluginProvider(p) {
9093
9031
  let loading;
9094
- const load = () => loading ??= import("./plugins-9en8m9y0.js").then((m) => m.loadPublishFunction(p));
9032
+ const load = () => loading ??= import("./plugins-4vaf27n9.js").then((m) => m.loadPublishFunction(p));
9095
9033
  return {
9096
9034
  info: infoFor(p),
9097
9035
  async authenticate() {
@@ -9365,10 +9303,10 @@ async function disconnectPublishCredential(key, deps, options = {}) {
9365
9303
  }
9366
9304
  }
9367
9305
  // src/lib/manifest-config.ts
9368
- import { isSeq as isSeq2, isMap as isMap3, YAMLSeq, Scalar as Scalar2 } from "yaml";
9306
+ import { isSeq as isSeq2, isMap as isMap3, YAMLSeq, Scalar } from "yaml";
9369
9307
  // src/lib/version-changes.ts
9370
9308
  import git3 from "isomorphic-git";
9371
- import postcss6 from "postcss";
9309
+ import postcss5 from "postcss";
9372
9310
 
9373
9311
  // src/lib/remote-auth/transport.ts
9374
9312
  import git2 from "isomorphic-git";
@@ -9578,4 +9516,4 @@ function normalizeProjectKey(projectDir) {
9578
9516
  }
9579
9517
  // src/lib/publish/manifest-publish.ts
9580
9518
  import { isMap as isMap4 } from "yaml";
9581
- export { reportMissingTools, executeValidation, executeAndReport, splitOutPath, runBuild, openPath, startPreviewServer, BUILT_IN_TEMPLATE_IDS, scaffoldProject, EXTENSION_KINDS, scaffoldExtension, importExtensionFromFile, importExtensionFromUrl, searchNpmExtensions, publishCredentialKey, publishConnectionStatus, listPublishAccounts, connectGoogleDrive, listBookPublishProviders, resolvePublishProvider, resolvePublishFormat, runPublish, connectPublishProvider, disconnectPublishCredential };
9519
+ export { reportMissingTools, executeValidation, executeAndReport, splitOutPath, runBuild, openPath, startPreviewServer, scaffoldProject, EXTENSION_KINDS, scaffoldExtension, BUILT_IN_TEMPLATE_IDS, importExtensionFromFile, importExtensionFromUrl, searchNpmExtensions, publishCredentialKey, publishConnectionStatus, listPublishAccounts, connectGoogleDrive, listBookPublishProviders, resolvePublishProvider, resolvePublishFormat, runPublish, connectPublishProvider, disconnectPublishCredential };
@@ -1,7 +1,7 @@
1
1
  // package.json
2
2
  var package_default = {
3
3
  name: "gutterpress",
4
- version: "0.11.23-alpha.1",
4
+ version: "0.11.23-alpha.3",
5
5
  description: "Markdown-to-PDF converter for professional print layout using a native Chromium print engine and Ghostscript.",
6
6
  author: "itlackey",
7
7
  license: "MPL-2.0",
@@ -4,9 +4,10 @@ import {
4
4
  findEnclosingRepoDir
5
5
  } from "./cli-v5mp7a6q.js";
6
6
  import {
7
- PLUGINS_DIR,
7
+ EXTENSIONS_DIR,
8
+ LEGACY_PLUGINS_DIR,
8
9
  VENDORED_NPM_DIR
9
- } from "./cli-h3phdstf.js";
10
+ } from "./cli-y28j019d.js";
10
11
 
11
12
  // src/lib/git-fs.ts
12
13
  import * as nodeFs from "node:fs";
@@ -511,10 +512,10 @@ async function countUnversionedChanges(projectDir) {
511
512
  return null;
512
513
  const dir = gitScopeFor(source);
513
514
  const bookPrefix = source.subPath ? `${source.subPath.replace(/\/+$/, "")}/` : "";
514
- const appWritten = `${bookPrefix}${PLUGINS_DIR}/${VENDORED_NPM_DIR}/`;
515
+ const appWritten = [EXTENSIONS_DIR, LEGACY_PLUGINS_DIR].map((d) => `${bookPrefix}${d}/${VENDORED_NPM_DIR}/`);
515
516
  return withRepoLock(dir, async () => {
516
517
  const { adds, removes } = await listWorkdirChanges(dir);
517
- const mine = new Set([...adds, ...removes].filter((f) => f.startsWith(bookPrefix) && !f.startsWith(appWritten)));
518
+ const mine = new Set([...adds, ...removes].filter((f) => f.startsWith(bookPrefix) && !appWritten.some((p) => f.startsWith(p))));
518
519
  return { changedFiles: mine.size, stale: gitFs.existsSync(snapshotStagingMarkerPath(dir)) };
519
520
  });
520
521
  }