gutterpress 0.11.23-alpha.3 → 0.11.23-alpha.5

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 (75) hide show
  1. package/README.md +4 -6
  2. package/dist/{README-8db7btxb.md → README-syg2hn83.md} +1 -1
  3. package/dist/api/index.d.ts +1 -1
  4. package/dist/api/index.js +7 -5
  5. package/dist/{build-m78jcpf7.js → build-4qv9wvrx.js} +8 -8
  6. package/dist/checks/asset/extensions.d.ts +1 -1
  7. package/dist/checks/asset/index.d.ts +0 -1
  8. package/dist/checks/policy.d.ts +5 -4
  9. package/dist/checks/source/config-file.d.ts +9 -6
  10. package/dist/checks/source/dangling-links.d.ts +1 -1
  11. package/dist/checks/types.d.ts +2 -2
  12. package/dist/{cli-s6djx4ma.js → cli-2t3krcfy.js} +1 -1
  13. package/dist/{cli-xsrffqzt.js → cli-58fsk6d7.js} +9 -9
  14. package/dist/{cli-2ppw6q9v.js → cli-5crpmz42.js} +80 -1
  15. package/dist/{cli-t8be9yeb.js → cli-de8ydmm7.js} +12 -7
  16. package/dist/{cli-n2tsxqpn.js → cli-nk0efg2x.js} +7 -2
  17. package/dist/{cli-1h17ktsg.js → cli-pth362d8.js} +139 -222
  18. package/dist/{cli-h4x81x97.js → cli-w97xcpag.js} +207 -142
  19. package/dist/{cli-5jzyw06s.js → cli-yxfznmsq.js} +1 -1
  20. package/dist/cli.js +12 -12
  21. package/dist/{doctor-j71jqce3.js → doctor-5nh3t346.js} +4 -3
  22. package/dist/{engine-m4y10shc.js → engine-4rabsgwq.js} +1 -1
  23. package/dist/{engine-1r6q80tq.js → engine-wm4fggac.js} +2 -2
  24. package/dist/{ext-fq2hg9va.js → ext-nhcep6h6.js} +8 -8
  25. package/dist/{extension-restore-9dh7c4tp.js → extension-restore-55kp0ksq.js} +2 -2
  26. package/dist/{extension-restore-tmxtzkm0.js → extension-restore-x3mtn844.js} +4 -4
  27. package/dist/{index-nedd07bk.js → index-2vxzxyyj.js} +9 -9
  28. package/dist/{index-2ppw6q9v.js → index-5crpmz42.js} +80 -1
  29. package/dist/{index-0wee4408.js → index-9ye22m7r.js} +12 -7
  30. package/dist/{index-prqvz3xm.js → index-agrkfbkv.js} +217 -244
  31. package/dist/{index-7pck1q9c.js → index-t3jkavdz.js} +206 -141
  32. package/dist/{index-nvmf22rt.js → index-wm4x7xbf.js} +1 -1
  33. package/dist/index.js +8 -6
  34. package/dist/lib/build-preflight.d.ts +4 -10
  35. package/dist/lib/build-runner.d.ts +1 -1
  36. package/dist/lib/ghostscript.d.ts +5 -2
  37. package/dist/lib/lint-rules.d.ts +5 -1
  38. package/dist/lib/manifest-config.d.ts +3 -2
  39. package/dist/lib/manifest-old-spellings.d.ts +64 -0
  40. package/dist/lib/markdown/chapter-id.d.ts +1 -1
  41. package/dist/lib/markdown/index.d.ts +1 -1
  42. package/dist/lib/markdown/table.d.ts +5 -3
  43. package/dist/lib/page-size.d.ts +14 -9
  44. package/dist/lib/pdf-inspect.d.ts +27 -0
  45. package/dist/lib/presets.d.ts +10 -8
  46. package/dist/lib/printsafe.d.ts +1 -1
  47. package/dist/lib/project-scaffold.d.ts +1 -1
  48. package/dist/lib/publish/connect.d.ts +8 -1
  49. package/dist/lib/publish/manifest-publish.d.ts +26 -2
  50. package/dist/lib/publish/selections.d.ts +12 -1
  51. package/dist/lib/publish/types.d.ts +15 -5
  52. package/dist/lib/remote-auth/sync-messages.d.ts +2 -2
  53. package/dist/lib/targets.d.ts +4 -4
  54. package/dist/lib/validation-exec.d.ts +4 -4
  55. package/dist/{manifest-my7mdv8j.yaml → manifest-2kc56wvw.yaml} +3 -4
  56. package/dist/{manifest-8afhrk30.yaml → manifest-41ddzm13.yaml} +3 -4
  57. package/dist/{manifest-gf13sjp8.yaml → manifest-79zsgkpn.yaml} +3 -4
  58. package/dist/{manifest-d4f9q79e.yaml → manifest-sqzm4681.yaml} +3 -4
  59. package/dist/{manifest.schema-650pe0d1.json → manifest.schema-93sd7zje.json} +32 -315
  60. package/dist/{new-s4zcaepg.js → new-5a4w2vkh.js} +9 -15
  61. package/dist/{page-rules-fj09xct5.css → page-rules-ytj9p04v.css} +1 -1
  62. package/dist/{pdf-inspect-wnw4za71.js → pdf-inspect-b3mf81ex.js} +3 -1
  63. package/dist/{plugins-4vaf27n9.js → plugins-cfzf26b8.js} +3 -3
  64. package/dist/{plugins-80emnf31.js → plugins-mm8270tn.js} +1 -1
  65. package/dist/{preflight-c7w1xdn3.js → preflight-jma71n0j.js} +8 -8
  66. package/dist/preview/file-watcher.d.ts +1 -3
  67. package/dist/{preview-interface-nnmrxyqm.js → preview-interface-0xdh0r5b.js} +3 -66
  68. package/dist/{preview-mzytcwyk.js → preview-kmx4h7gv.js} +8 -8
  69. package/dist/{publish-fez14ad4.js → publish-62843020.js} +8 -8
  70. package/dist/render.js +6 -1
  71. package/dist/schema/manifest.types.d.ts +58 -110
  72. package/dist/{tokens-ye64p899.css → tokens-n82t4k9h.css} +11 -4
  73. package/dist/{validate-p2chr6hr.js → validate-vvmrd85g.js} +8 -8
  74. package/package.json +1 -1
  75. package/dist/checks/asset/approved-fonts.d.ts +0 -3
@@ -11,10 +11,10 @@ import {
11
11
  prettify,
12
12
  readExtensionMeta,
13
13
  slugify
14
- } from "./cli-t8be9yeb.js";
14
+ } from "./cli-de8ydmm7.js";
15
15
  import {
16
16
  log
17
- } from "./cli-s6djx4ma.js";
17
+ } from "./cli-2t3krcfy.js";
18
18
  import {
19
19
  UsageError
20
20
  } from "./cli-d8xjns66.js";
@@ -185,9 +185,7 @@ var DTRPG_PRESET = {
185
185
  },
186
186
  defaultTargets: ["dtrpg"],
187
187
  extensions: [],
188
- source: {
189
- files: null
190
- },
188
+ chapters: null,
191
189
  print: { signature: 4, reserveLastPage: true, lastPage: undefined },
192
190
  pdfx: {
193
191
  flavor: "x1a",
@@ -212,53 +210,23 @@ var DTRPG_PRESET = {
212
210
  maxTac: 240,
213
211
  tacTolerance: 0.5
214
212
  },
215
- lint: {
216
- enabled: true,
217
- configPath: null,
218
- rules: {}
213
+ checks: {
214
+ "pdf.structure.qpdf": "error",
215
+ "pdf.print.pdfx-markers": "error",
216
+ "pdf.print.pdfx-metadata": "error",
217
+ "pdf.print.embedded-fonts": "error",
218
+ "pdf.print.safe-margins": "error",
219
+ "pdf.print.bleed": "off",
220
+ "pdf.nav.bookmarks": "off",
221
+ "pdf.nav.toc-links": "off",
222
+ "asset.font.license": "off"
219
223
  },
220
224
  validate: {
221
- enabled: true,
222
- checks: {
223
- "pdf.structure.qpdf": {
224
- enabled: true,
225
- severity: "error"
226
- },
227
- "pdf.print.pdfx-markers": {
228
- enabled: true,
229
- severity: "error"
230
- },
231
- "pdf.print.pdfx-metadata": {
232
- enabled: true,
233
- severity: "error"
234
- },
235
- "pdf.print.embedded-fonts": {
236
- enabled: true,
237
- severity: "error"
238
- },
239
- "pdf.print.safe-margins": {
240
- enabled: true,
241
- severity: "error"
242
- }
243
- },
244
- source: {
245
- markdownlint: null,
246
- htmlhint: null,
247
- stylelint: null,
248
- cssOwnership: null
249
- },
250
225
  assets: {
251
- maxImageSize: 1e7,
252
- allowAlpha: false,
253
- approvedFontFiles: [],
254
- requireFontLicense: false
226
+ maxImageSize: 1e7
255
227
  },
256
228
  pdf: {
257
- requireBookmarks: false,
258
- requireTocLinks: false,
259
229
  minImageResolution: 300,
260
- forbidTransparency: true,
261
- requireBleed: false,
262
230
  bleedSize: 9
263
231
  },
264
232
  heuristics: {
@@ -272,9 +240,7 @@ var BOOK_PRESET = {
272
240
  id: "book",
273
241
  defaultTargets: [],
274
242
  extensions: [],
275
- source: {
276
- files: null
277
- },
243
+ chapters: null,
278
244
  print: { signature: 1, reserveLastPage: false, lastPage: undefined },
279
245
  pdfx: {
280
246
  flavor: "x1a",
@@ -299,47 +265,25 @@ var BOOK_PRESET = {
299
265
  maxTac: 400,
300
266
  tacTolerance: 0.5
301
267
  },
302
- lint: {
303
- enabled: true,
304
- configPath: null,
305
- rules: {}
268
+ checks: {
269
+ "pdf.structure.qpdf": "error",
270
+ "pdf.print.embedded-fonts": "error",
271
+ "pdf.print.safe-margins": "warning",
272
+ "pdf.print.pdfx-markers": "off",
273
+ "pdf.print.pdfx-metadata": "off",
274
+ "pdf.print.transparency": "off",
275
+ "asset.image.alpha-channel": "off",
276
+ "pdf.print.bleed": "off",
277
+ "pdf.nav.bookmarks": "off",
278
+ "pdf.nav.toc-links": "off",
279
+ "asset.font.license": "off"
306
280
  },
307
281
  validate: {
308
- enabled: true,
309
- checks: {
310
- "pdf.structure.qpdf": {
311
- enabled: true,
312
- severity: "error"
313
- },
314
- "pdf.print.embedded-fonts": {
315
- enabled: true,
316
- severity: "error"
317
- },
318
- "pdf.print.safe-margins": {
319
- enabled: true,
320
- severity: "warning"
321
- },
322
- "pdf.print.pdfx-markers": false,
323
- "pdf.print.pdfx-metadata": false
324
- },
325
- source: {
326
- markdownlint: null,
327
- htmlhint: null,
328
- stylelint: null,
329
- cssOwnership: null
330
- },
331
282
  assets: {
332
- maxImageSize: 1e7,
333
- allowAlpha: true,
334
- approvedFontFiles: [],
335
- requireFontLicense: false
283
+ maxImageSize: 1e7
336
284
  },
337
285
  pdf: {
338
- requireBookmarks: false,
339
- requireTocLinks: false,
340
286
  minImageResolution: 300,
341
- forbidTransparency: false,
342
- requireBleed: false,
343
287
  bleedSize: 9
344
288
  },
345
289
  heuristics: {
@@ -392,16 +336,16 @@ var DTRPG_TARGET = {
392
336
  maxTac: DTRPG_PRESET.ink.maxTac,
393
337
  tacTolerance: DTRPG_PRESET.ink.tacTolerance
394
338
  },
339
+ checks: {
340
+ "pdf.structure.qpdf": "error",
341
+ "pdf.print.pdfx-markers": "error",
342
+ "pdf.print.pdfx-metadata": "error",
343
+ "pdf.print.embedded-fonts": "error",
344
+ "pdf.print.safe-margins": "error",
345
+ "pdf.print.transparency": "on"
346
+ },
395
347
  validate: {
396
- checks: {
397
- "pdf.structure.qpdf": { enabled: true, severity: "error" },
398
- "pdf.print.pdfx-markers": { enabled: true, severity: "error" },
399
- "pdf.print.pdfx-metadata": { enabled: true, severity: "error" },
400
- "pdf.print.embedded-fonts": { enabled: true, severity: "error" },
401
- "pdf.print.safe-margins": { enabled: true, severity: "error" }
402
- },
403
348
  pdf: {
404
- forbidTransparency: DTRPG_PRESET.validate.pdf.forbidTransparency,
405
349
  minImageResolution: DTRPG_PRESET.validate.pdf.minImageResolution
406
350
  }
407
351
  }
@@ -419,22 +363,22 @@ var ITCH_TARGET = {
419
363
  id: "itch",
420
364
  label: "itch.io",
421
365
  overlay: {
366
+ checks: {
367
+ "pdf.structure.qpdf": "error",
368
+ "pdf.print.embedded-fonts": "error",
369
+ "pdf.print.pdfx-markers": "off",
370
+ "pdf.print.pdfx-metadata": "off",
371
+ "pdf.print.ink-coverage": "off",
372
+ "pdf.print.safe-margins": "off",
373
+ "pdf.print.transparency": "off",
374
+ "pdf.print.bleed": "off",
375
+ "asset.image.alpha-channel": "off"
376
+ },
422
377
  validate: {
423
- checks: {
424
- "pdf.structure.qpdf": { enabled: true, severity: "error" },
425
- "pdf.print.embedded-fonts": { enabled: true, severity: "error" },
426
- "pdf.print.pdfx-markers": false,
427
- "pdf.print.pdfx-metadata": false,
428
- "pdf.print.ink-coverage": false,
429
- "pdf.print.safe-margins": false
430
- },
431
378
  assets: {
432
- allowAlpha: true,
433
379
  maxImageSize: 0
434
380
  },
435
381
  pdf: {
436
- forbidTransparency: false,
437
- requireBleed: false,
438
382
  minImageResolution: 0
439
383
  }
440
384
  }
@@ -473,9 +417,9 @@ function overlayPreset(preset, target) {
473
417
  ...preset,
474
418
  pdfx: { ...preset.pdfx, ...o.pdfx },
475
419
  ink: { ...preset.ink, ...o.ink },
420
+ checks: { ...preset.checks, ...o.checks },
476
421
  validate: {
477
422
  ...preset.validate,
478
- checks: { ...preset.validate.checks, ...o.validate?.checks },
479
423
  assets: { ...preset.validate.assets, ...o.validate?.assets },
480
424
  pdf: { ...preset.validate.pdf, ...o.validate?.pdf }
481
425
  }
@@ -490,13 +434,120 @@ var DEFAULT_STRICT_PDF_CHECKS = [
490
434
  function applyDefaultPdfStrictChecks(config) {
491
435
  const next = structuredClone(config);
492
436
  for (const checkId of DEFAULT_STRICT_PDF_CHECKS) {
493
- if (next.validate.checks[checkId] === undefined) {
494
- next.validate.checks[checkId] = { enabled: true, severity: "error" };
495
- }
437
+ if (next.checks[checkId] === undefined)
438
+ next.checks[checkId] = "error";
496
439
  }
497
440
  return next;
498
441
  }
499
442
 
443
+ // src/lib/manifest-old-spellings.ts
444
+ var SOURCE_TOOL_CHECKS = {
445
+ markdownlint: "source.markdownlint",
446
+ htmlhint: "source.htmlhint",
447
+ stylelint: "source.stylelint",
448
+ cssOwnership: "source.css-ownership"
449
+ };
450
+ var FLAG_CHECKS = {
451
+ "assets.allowAlpha": { check: "asset.image.alpha-channel", trueMeansOn: false },
452
+ "assets.requireFontLicense": { check: "asset.font.license", trueMeansOn: true },
453
+ "pdf.requireBookmarks": { check: "pdf.nav.bookmarks", trueMeansOn: true },
454
+ "pdf.requireTocLinks": { check: "pdf.nav.toc-links", trueMeansOn: true },
455
+ "pdf.requireBleed": { check: "pdf.print.bleed", trueMeansOn: true },
456
+ "pdf.forbidTransparency": { check: "pdf.print.transparency", trueMeansOn: true }
457
+ };
458
+ function isObject(v) {
459
+ return typeof v === "object" && v !== null && !Array.isArray(v);
460
+ }
461
+ function readOldSpellings(raw) {
462
+ const { source, lint, validate, ink, ...manifest } = raw;
463
+ const tolerance = isObject(raw.page) && "tolerance" in raw.page;
464
+ if (source === undefined && lint === undefined && validate === undefined && ink === undefined && !tolerance) {
465
+ return raw;
466
+ }
467
+ if (isObject(source) && source.assets !== undefined) {
468
+ throw new UsageError("Manifest field `source.assets` is no longer supported — remove it.\n" + " Assets are discovered from what your book actually references, so no list is needed.");
469
+ }
470
+ const renamed = [];
471
+ const dropped = [];
472
+ const checks = {};
473
+ if (isObject(source) && "files" in source) {
474
+ renamed.push("source.files -> chapters");
475
+ if (manifest.chapters === undefined)
476
+ manifest.chapters = source.files ?? null;
477
+ }
478
+ if (isObject(validate)) {
479
+ for (const [id, entry] of Object.entries(validate.checks ?? {})) {
480
+ if (entry === false || isObject(entry) && entry.enabled === false)
481
+ checks[id] = "off";
482
+ else if (isObject(entry) && typeof entry.severity === "string")
483
+ checks[id] = entry.severity;
484
+ else
485
+ checks[id] = "on";
486
+ }
487
+ if (validate.checks !== undefined)
488
+ renamed.push("validate.checks -> checks");
489
+ for (const [tool, value] of Object.entries(validate.source ?? {})) {
490
+ const id = SOURCE_TOOL_CHECKS[tool];
491
+ if (id && value === false) {
492
+ checks[id] = "off";
493
+ renamed.push(`validate.source.${tool}: false -> checks: { ${id}: off }`);
494
+ } else if (id && tool !== "stylelint" && typeof value === "string") {
495
+ dropped.push(`validate.source.${tool} (the config file is found by its usual name in the book's folder or a folder above it)`);
496
+ } else {
497
+ dropped.push(`validate.source.${tool}`);
498
+ }
499
+ }
500
+ for (const block of ["assets", "pdf", "heuristics"]) {
501
+ for (const [key, value] of Object.entries(validate[block] ?? {})) {
502
+ const flag = FLAG_CHECKS[`${block}.${key}`];
503
+ if (flag && typeof value === "boolean") {
504
+ const level = value === flag.trueMeansOn ? "on" : "off";
505
+ checks[flag.check] = level;
506
+ renamed.push(`validate.${block}.${key}: ${value} -> checks: { ${flag.check}: ${level} }`);
507
+ } else {
508
+ dropped.push(`validate.${block}.${key} (the preset and the publish target set it)`);
509
+ }
510
+ }
511
+ }
512
+ if (validate.enabled !== undefined) {
513
+ dropped.push("validate.enabled (`gutterpress build --skip-pre-validate --skip-post-validate` skips validation for one build)");
514
+ }
515
+ }
516
+ if (isObject(lint)) {
517
+ for (const [id, level] of Object.entries(lint.rules ?? {}))
518
+ checks[id] = level;
519
+ if (lint.rules !== undefined)
520
+ renamed.push("lint.rules -> checks");
521
+ if (lint.enabled === false) {
522
+ checks["source.stylelint"] = "off";
523
+ renamed.push("lint.enabled: false -> checks: { source.stylelint: off }");
524
+ } else if (lint.enabled !== undefined) {
525
+ dropped.push("lint.enabled");
526
+ }
527
+ if (lint.configPath !== undefined)
528
+ dropped.push("lint.configPath");
529
+ }
530
+ if (ink !== undefined)
531
+ dropped.push("ink (the preset and the publish target set it)");
532
+ if (tolerance) {
533
+ const { tolerance: _, ...page } = raw.page;
534
+ manifest.page = page;
535
+ dropped.push("page.tolerance (the preset sets it)");
536
+ }
537
+ if (Object.keys(checks).length > 0)
538
+ manifest.checks = { ...checks, ...manifest.checks };
539
+ const lines = [
540
+ ...renamed.map((r) => ` ${r}`),
541
+ ...dropped.map((d) => ` ${d} — no longer a setting, ignored`)
542
+ ];
543
+ if (lines.length > 0) {
544
+ warnOnce(`old-manifest-spellings:${lines.join("|")}`, "[gutterpress] manifest.yaml uses spellings 0.11.23 replaced. They still work in this " + `release; rewrite them before the next one:
545
+ ` + lines.join(`
546
+ `));
547
+ }
548
+ return manifest;
549
+ }
550
+
500
551
  // src/lib/manifest.ts
501
552
  var MANIFEST_FILENAMES = [
502
553
  "manifest.yaml"
@@ -514,8 +565,8 @@ async function loadManifestWithPath(pathOrDir, opts) {
514
565
  throw new UsageError(`"${p}" has two versions of a setting — yours and the online version — left by a sync. Open it, keep the one you want and delete the marker lines.`);
515
566
  }
516
567
  try {
517
- const manifest = parseYaml(raw) ?? {};
518
- return { manifest, manifestDir: dirname(p), manifestPath: p };
568
+ const parsed = parseYaml(raw) ?? {};
569
+ return { manifest: readOldSpellings(parsed), manifestDir: dirname(p), manifestPath: p };
519
570
  } catch (error) {
520
571
  if (!(error instanceof YAMLParseError))
521
572
  throw error;
@@ -651,7 +702,7 @@ function resolveCustomPage(c, m) {
651
702
  return {
652
703
  width,
653
704
  height,
654
- tolerance: c.page?.tolerance ?? m.page?.tolerance ?? 0.5,
705
+ tolerance: 0.5,
655
706
  bleed: c.page?.bleed ?? m.page?.bleed,
656
707
  safe: c.page?.safe ?? m.page?.safe,
657
708
  artSafe: c.page?.artSafe ?? m.page?.artSafe,
@@ -680,22 +731,8 @@ function validatePageMargin(margin, size) {
680
731
  function resolveWithPreset(cliOverrides, manifest, preset) {
681
732
  const m = manifest;
682
733
  const c = cliOverrides;
683
- const legacy = m;
684
- if (legacy.output !== undefined || legacy.source?.assets !== undefined) {
685
- const stale = [
686
- legacy.output !== undefined ? "`output`" : null,
687
- legacy.source?.assets !== undefined ? "`source.assets`" : null
688
- ].filter(Boolean);
689
- throw new UsageError(`Manifest field(s) ${stale.join(" and ")} are no longer supported — remove them.
690
- ` + " Output goes to `dist/<title-slug>/` automatically (use `--out` for a one-off location).\n" + " Assets are discovered from what your book actually references, so no list is needed.");
691
- }
692
- if ((m.validate?.source?.allowedCallouts?.length ?? 0) > 0 || (c.validate?.source?.allowedCallouts?.length ?? 0) > 0) {
693
- warnOnce("allowed-callouts-deprecated", "[gutterpress] manifest field `validate.source.allowedCallouts` is " + "deprecated and ignored. The `:::` container syntax it gated was " + "removed 2026-05-17. See docs/migrations/2026-05-removing-container-syntax.md.");
694
- }
695
- for (const key of ["minImageDpi", "allowedColorSpaces"]) {
696
- if (m.validate?.assets?.[key] !== undefined || c.validate?.assets?.[key] !== undefined) {
697
- warnOnce(`assets-${key}-deprecated`, `[gutterpress] manifest field \`validate.assets.${key}\` is deprecated and ` + "ignored. The source-image check it configured was removed; the build " + "and the PDF checks measure what actually prints.");
698
- }
734
+ if (m.output !== undefined) {
735
+ throw new UsageError("Manifest field `output` is no longer supported — remove it.\n" + " Output goes to `dist/<title-slug>/` automatically (use `--out` for a one-off location).");
699
736
  }
700
737
  const removed = m;
701
738
  if (removed.engine !== undefined) {
@@ -741,25 +778,37 @@ function resolveWithPreset(cliOverrides, manifest, preset) {
741
778
  styles: c.styles ?? m.styles,
742
779
  extensions,
743
780
  targets: resolveTargets(c.targets ?? m.targets, preset.defaultTargets),
744
- source: mergeShape(c.source, m.source, preset.source),
781
+ chapters: c.chapters ?? m.chapters ?? preset.chapters,
782
+ checks: { ...preset.checks, ...resolveCheckLevels(m.checks), ...resolveCheckLevels(c.checks) },
745
783
  pdfx: mergeShape(c.pdfx, m.pdfx, preset.pdfx),
746
784
  print: mergeShape(c.print, m.print, preset.print),
747
785
  page,
748
- ink: mergeShape(c.ink, m.ink, preset.ink),
749
- lint: {
750
- ...mergeShape(c.lint, m.lint, preset.lint),
751
- rules: { ...preset.lint.rules, ...m.lint?.rules, ...c.lint?.rules }
752
- },
753
- validate: {
754
- enabled: c.validate?.enabled ?? m.validate?.enabled ?? preset.validate.enabled,
755
- checks: { ...preset.validate.checks, ...m.validate?.checks, ...c.validate?.checks },
756
- source: mergeShape(c.validate?.source, m.validate?.source, preset.validate.source),
757
- assets: mergeShape(c.validate?.assets, m.validate?.assets, preset.validate.assets),
758
- pdf: mergeShape(c.validate?.pdf, m.validate?.pdf, preset.validate.pdf),
759
- heuristics: mergeShape(c.validate?.heuristics, m.validate?.heuristics, preset.validate.heuristics)
760
- }
786
+ ink: structuredClone(preset.ink),
787
+ validate: structuredClone(preset.validate)
761
788
  };
762
789
  }
790
+ function resolveCheckLevels(input) {
791
+ if (input === undefined || input === null)
792
+ return {};
793
+ if (!isPlainObject(input)) {
794
+ throw new UsageError("Manifest field `checks` must map check ids to off, on, info, warn or error.");
795
+ }
796
+ const out = {};
797
+ for (const [id, value] of Object.entries(input)) {
798
+ if (value === false || value === "off")
799
+ out[id] = "off";
800
+ else if (value === true || value === "on")
801
+ out[id] = "on";
802
+ else if (value === "warn" || value === "warning")
803
+ out[id] = "warning";
804
+ else if (value === "info" || value === "error")
805
+ out[id] = value;
806
+ else {
807
+ throw new UsageError(`Manifest field \`checks.${id}\` must be off, on, info, warn or error, got ${JSON.stringify(value)}.`);
808
+ }
809
+ }
810
+ return out;
811
+ }
763
812
 
764
813
  // src/lib/manifest-doc.ts
765
814
  function resolveManifestPath(projectDir) {
@@ -1478,6 +1527,7 @@ function ignoreStatus(gitignore, entry) {
1478
1527
  return dir.unignored || file.unignored ? "negated" : "open";
1479
1528
  }
1480
1529
  var PROJECT_GITIGNORE_ENTRIES = ["dist/", "extensions/npm/"];
1530
+ var LEGACY_NPM_LINE = /^\/?plugins\/npm\/?[ \t]*\r?\n?/gm;
1481
1531
  async function ensureProjectGitignore(projectDir) {
1482
1532
  const gitignorePath = path3.join(projectDir, ".gitignore");
1483
1533
  let existing = null;
@@ -1494,10 +1544,11 @@ async function ensureProjectGitignore(projectDir) {
1494
1544
  negated.push(entry);
1495
1545
  }
1496
1546
  if (missing.length > 0) {
1497
- const lead = existing !== null && existing.length > 0 && !existing.endsWith(`
1547
+ const kept = missing.includes("extensions/npm/") ? (existing ?? "").replace(LEGACY_NPM_LINE, "") : existing ?? "";
1548
+ const lead = kept.length > 0 && !kept.endsWith(`
1498
1549
  `) ? `
1499
1550
  ` : "";
1500
- await writeFile(gitignorePath, `${existing ?? ""}${lead}${missing.join(`
1551
+ await writeFile(gitignorePath, `${kept}${lead}${missing.join(`
1501
1552
  `)}
1502
1553
  `, "utf8");
1503
1554
  }
@@ -1867,6 +1918,7 @@ async function vendorNpmExtension(projectDir, input, exportName, options, commit
1867
1918
  await finalizeNpmPluginInstall(installed).catch((error) => {
1868
1919
  warnings.push(`The extension was installed, but an old backup could not be removed: ` + `${error instanceof Error ? error.message : String(error)}`);
1869
1920
  });
1921
+ warnings.push(...await retireLegacyCopies(projectDir, installed.name));
1870
1922
  try {
1871
1923
  const { negated } = await ensureProjectGitignore(projectDir);
1872
1924
  if (negated.includes("extensions/npm/")) {
@@ -1877,6 +1929,19 @@ async function vendorNpmExtension(projectDir, input, exportName, options, commit
1877
1929
  }
1878
1930
  return { name: installed.name, version: installed.version, use, warnings };
1879
1931
  }
1932
+ async function retireLegacyCopies(projectDir, name) {
1933
+ const legacyPackageDir = path4.dirname(vendoredNpmPluginRoots(projectDir, name, "0.0.0")[1]);
1934
+ const legacyNpmDir = path4.dirname(legacyPackageDir);
1935
+ try {
1936
+ await rm3(legacyPackageDir, { recursive: true, force: true });
1937
+ await removeEmptyDirs([path4.dirname(legacyNpmDir), legacyNpmDir]);
1938
+ } catch (error) {
1939
+ return [
1940
+ `The extension was installed, but the copy an older version of Gutterpress kept under plugins/npm/ ` + `could not be removed: ${error instanceof Error ? error.message : String(error)}`
1941
+ ];
1942
+ }
1943
+ return [];
1944
+ }
1880
1945
  async function pinnedVersionsOf(projectDir, name) {
1881
1946
  const { doc } = await loadManifestDoc(projectDir);
1882
1947
  const seq = doc.get("extensions", true);
@@ -1,7 +1,7 @@
1
1
  // package.json
2
2
  var package_default = {
3
3
  name: "gutterpress",
4
- version: "0.11.23-alpha.3",
4
+ version: "0.11.23-alpha.5",
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",
package/dist/cli.js CHANGED
@@ -8,7 +8,7 @@ import {
8
8
  } from "./cli-d8xjns66.js";
9
9
  import {
10
10
  package_default
11
- } from "./cli-5jzyw06s.js";
11
+ } from "./cli-yxfznmsq.js";
12
12
  import {
13
13
  EXIT_CODES
14
14
  } from "./cli-46ycxe6r.js";
@@ -20,14 +20,14 @@ import {
20
20
  import { defineCommand, parseArgs, runMain } from "citty";
21
21
  import { statSync } from "node:fs";
22
22
  var SUBCOMMANDS = {
23
- new: () => import("./new-s4zcaepg.js").then((m) => m.default),
24
- preview: () => import("./preview-mzytcwyk.js").then((m) => m.default),
25
- build: () => import("./build-m78jcpf7.js").then((m) => m.default),
26
- publish: () => import("./publish-fez14ad4.js").then((m) => m.default),
27
- validate: () => import("./validate-p2chr6hr.js").then((m) => m.default),
28
- preflight: () => import("./preflight-c7w1xdn3.js").then((m) => m.default),
29
- doctor: () => import("./doctor-j71jqce3.js").then((m) => m.default),
30
- ext: () => import("./ext-fq2hg9va.js").then((m) => m.default)
23
+ new: () => import("./new-5a4w2vkh.js").then((m) => m.default),
24
+ preview: () => import("./preview-kmx4h7gv.js").then((m) => m.default),
25
+ build: () => import("./build-4qv9wvrx.js").then((m) => m.default),
26
+ publish: () => import("./publish-62843020.js").then((m) => m.default),
27
+ validate: () => import("./validate-vvmrd85g.js").then((m) => m.default),
28
+ preflight: () => import("./preflight-jma71n0j.js").then((m) => m.default),
29
+ doctor: () => import("./doctor-5nh3t346.js").then((m) => m.default),
30
+ ext: () => import("./ext-nhcep6h6.js").then((m) => m.default)
31
31
  };
32
32
  var VERSION = package_default.version;
33
33
  var main = defineCommand({
@@ -52,7 +52,7 @@ async function preflightRequiredInvocations(rawArgs) {
52
52
  const [command, ...commandArgs] = rawArgs;
53
53
  try {
54
54
  if (command === "new") {
55
- const { newArgs } = await import("./new-s4zcaepg.js");
55
+ const { newArgs } = await import("./new-5a4w2vkh.js");
56
56
  rejectUnknownFlags(commandArgs, newArgs, "new");
57
57
  const parsed = parseArgs(commandArgs, {
58
58
  ...newArgs,
@@ -64,7 +64,7 @@ async function preflightRequiredInvocations(rawArgs) {
64
64
  return;
65
65
  }
66
66
  if (command === "preflight") {
67
- const { preflightArgs } = await import("./preflight-c7w1xdn3.js");
67
+ const { preflightArgs } = await import("./preflight-jma71n0j.js");
68
68
  rejectUnknownFlags(commandArgs, preflightArgs, "preflight");
69
69
  const parsed = parseArgs(commandArgs, {
70
70
  ...preflightArgs,
@@ -84,7 +84,7 @@ async function preflightRequiredInvocations(rawArgs) {
84
84
  }
85
85
  if (subcommand.startsWith("-"))
86
86
  return;
87
- const { EXT_SUBCOMMANDS, extAddArgs, extRemoveArgs, extEnableArgs, extDisableArgs } = await import("./ext-fq2hg9va.js");
87
+ const { EXT_SUBCOMMANDS, extAddArgs, extRemoveArgs, extEnableArgs, extDisableArgs } = await import("./ext-nhcep6h6.js");
88
88
  if (!EXT_SUBCOMMANDS.includes(subcommand)) {
89
89
  throw new UsageError(`gutterpress ext: unknown command "${subcommand}"`);
90
90
  }
@@ -1,16 +1,17 @@
1
1
  import {
2
2
  getSystemDiagnostics
3
- } from "./cli-n2tsxqpn.js";
3
+ } from "./cli-nk0efg2x.js";
4
+ import"./cli-5crpmz42.js";
4
5
  import"./cli-asap4t1z.js";
5
6
  import {
6
7
  log
7
- } from "./cli-s6djx4ma.js";
8
+ } from "./cli-2t3krcfy.js";
8
9
  import {
9
10
  UsageError,
10
11
  rejectExtraPositionals,
11
12
  rejectUnknownFlags
12
13
  } from "./cli-d8xjns66.js";
13
- import"./cli-5jzyw06s.js";
14
+ import"./cli-yxfznmsq.js";
14
15
  import"./cli-46ycxe6r.js";
15
16
  import"./cli-37x76zdn.js";
16
17
 
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  build
3
- } from "./cli-xsrffqzt.js";
3
+ } from "./cli-58fsk6d7.js";
4
4
  import"./cli-eyyggect.js";
5
5
  import"./cli-asap4t1z.js";
6
6
  import {
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  build
3
- } from "./index-nvmf22rt.js";
4
- import"./index-nedd07bk.js";
3
+ } from "./index-wm4x7xbf.js";
4
+ import"./index-2vxzxyyj.js";
5
5
  import {
6
6
  BuildError
7
7
  } from "./index-46ycxe6r.js";
@@ -2,11 +2,11 @@ import {
2
2
  importExtensionFromFile,
3
3
  importExtensionFromUrl,
4
4
  searchNpmExtensions
5
- } from "./cli-1h17ktsg.js";
6
- import"./cli-n2tsxqpn.js";
5
+ } from "./cli-pth362d8.js";
6
+ import"./cli-nk0efg2x.js";
7
7
  import"./cli-ht1bcqdd.js";
8
- import"./cli-xsrffqzt.js";
9
- import"./cli-2ppw6q9v.js";
8
+ import"./cli-58fsk6d7.js";
9
+ import"./cli-5crpmz42.js";
10
10
  import"./cli-eyyggect.js";
11
11
  import"./cli-asap4t1z.js";
12
12
  import"./cli-a35w7wzg.js";
@@ -18,12 +18,12 @@ import {
18
18
  removeExtension,
19
19
  setExtensionEnabled,
20
20
  updateExtensions
21
- } from "./cli-h4x81x97.js";
21
+ } from "./cli-w97xcpag.js";
22
22
  import {
23
23
  isPathSpecifier,
24
24
  parseExtensionSpecifier
25
- } from "./cli-t8be9yeb.js";
26
- import"./cli-s6djx4ma.js";
25
+ } from "./cli-de8ydmm7.js";
26
+ import"./cli-2t3krcfy.js";
27
27
  import {
28
28
  UsageError,
29
29
  exitForUsage,
@@ -31,7 +31,7 @@ import {
31
31
  rejectUnknownFlags,
32
32
  resolveProjectDir
33
33
  } from "./cli-d8xjns66.js";
34
- import"./cli-5jzyw06s.js";
34
+ import"./cli-yxfznmsq.js";
35
35
  import {
36
36
  EXIT_CODES
37
37
  } from "./cli-46ycxe6r.js";
@@ -3,8 +3,8 @@ import {
3
3
  restoreForCommand,
4
4
  restoreOfflineMessage,
5
5
  restorePinnedExtensions
6
- } from "./index-7pck1q9c.js";
7
- import"./index-0wee4408.js";
6
+ } from "./index-t3jkavdz.js";
7
+ import"./index-9ye22m7r.js";
8
8
  import"./index-46ycxe6r.js";
9
9
  import"./index-5x42amh8.js";
10
10
  import"./index-37x76zdn.js";
@@ -3,11 +3,11 @@ import {
3
3
  restoreForCommand,
4
4
  restoreOfflineMessage,
5
5
  restorePinnedExtensions
6
- } from "./cli-h4x81x97.js";
7
- import"./cli-t8be9yeb.js";
8
- import"./cli-s6djx4ma.js";
6
+ } from "./cli-w97xcpag.js";
7
+ import"./cli-de8ydmm7.js";
8
+ import"./cli-2t3krcfy.js";
9
9
  import"./cli-d8xjns66.js";
10
- import"./cli-5jzyw06s.js";
10
+ import"./cli-yxfznmsq.js";
11
11
  import"./cli-46ycxe6r.js";
12
12
  import"./cli-y28j019d.js";
13
13
  import"./cli-37x76zdn.js";