gutterpress 0.11.23-beta.2 → 0.11.23

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 (58) hide show
  1. package/README.md +12 -2
  2. package/dist/api/index.d.ts +5 -5
  3. package/dist/api/index.js +19 -7
  4. package/dist/{build-3e18wnqj.js → build-ph6jn930.js} +9 -9
  5. package/dist/checks/asset/approved-fonts.d.ts +8 -0
  6. package/dist/checks/asset/extensions.d.ts +1 -1
  7. package/dist/checks/asset/index.d.ts +1 -0
  8. package/dist/{cli-88arpdke.js → cli-axqsy7xn.js} +296 -65
  9. package/dist/{cli-9n9kg58f.js → cli-b8rmyy7t.js} +1 -1
  10. package/dist/{cli-x7gcdg6w.js → cli-ep43hgqb.js} +1 -1
  11. package/dist/{cli-v0evdpdf.js → cli-eymdsefg.js} +1 -1
  12. package/dist/{cli-pd2cje5b.js → cli-fsjre61x.js} +1 -1
  13. package/dist/{cli-0ep11b0q.js → cli-gy95bxec.js} +1 -1
  14. package/dist/{cli-pnrararp.js → cli-vqt6808y.js} +162 -55
  15. package/dist/{cli-tgnyvra3.js → cli-w6ywbxym.js} +35 -16
  16. package/dist/cli.js +12 -12
  17. package/dist/{doctor-2f4s9dyn.js → doctor-rx93cd3j.js} +3 -3
  18. package/dist/{engine-c4pxz79g.js → engine-17v87vq5.js} +1 -1
  19. package/dist/{engine-cs5g2ez0.js → engine-y9fnarfa.js} +2 -2
  20. package/dist/{ext-70gv86v5.js → ext-3b64v44z.js} +27 -10
  21. package/dist/{extension-restore-chj5nx3t.js → extension-restore-3yy4pzy9.js} +3 -3
  22. package/dist/{extension-restore-pd87p8r2.js → extension-restore-6hsxgmvn.js} +5 -5
  23. package/dist/{index-80vg3ed6.js → index-37cxffyb.js} +35 -16
  24. package/dist/{index-ytjkvwy5.js → index-7wgf4bqz.js} +321 -66
  25. package/dist/{index-swfdgn2n.js → index-d9w3r89w.js} +1 -1
  26. package/dist/{index-5x42amh8.js → index-g3te5ey1.js} +2 -1
  27. package/dist/{index-7j3hkwya.js → index-kw4tbthz.js} +1 -1
  28. package/dist/{index-0k43evt0.js → index-rzdn6r10.js} +186 -60
  29. package/dist/{index-2t1gdma7.js → index-santcs4q.js} +1 -1
  30. package/dist/index.js +35 -8
  31. package/dist/lib/check-options.d.ts +70 -0
  32. package/dist/lib/extension-manager.d.ts +16 -1
  33. package/dist/lib/extension-scaffold.d.ts +15 -2
  34. package/dist/lib/extension-specifier.d.ts +8 -1
  35. package/dist/lib/manifest-config.d.ts +3 -1
  36. package/dist/lib/manifest-old-spellings.d.ts +32 -9
  37. package/dist/lib/markdown/math.d.ts +1 -1
  38. package/dist/lib/markdown/typography.d.ts +1 -0
  39. package/dist/lib/page-size.d.ts +12 -4
  40. package/dist/lib/plugin-vendor.d.ts +6 -0
  41. package/dist/lib/presets.d.ts +2 -2
  42. package/dist/lib/root-tokens.d.ts +2 -1
  43. package/dist/lib/style-resolver.d.ts +2 -1
  44. package/dist/lib/version-changes.d.ts +9 -3
  45. package/dist/{manifest.schema-0jgj0jt1.json → manifest.schema-5cm13vr3.json} +215 -5
  46. package/dist/{new-d61n5cn0.js → new-3xrnhzr8.js} +22 -15
  47. package/dist/{plugins-0hhw6s17.js → plugins-1ed7bbxn.js} +2 -2
  48. package/dist/{plugins-e0n46s6m.js → plugins-ar5wrek4.js} +4 -4
  49. package/dist/{preflight-fjayhjr5.js → preflight-shmd1cnr.js} +9 -9
  50. package/dist/{preview-h815jrfb.js → preview-dadmsstg.js} +9 -9
  51. package/dist/{publish-ft39zgma.js → publish-s7vb3q2y.js} +9 -9
  52. package/dist/render.js +43 -11
  53. package/dist/schema/manifest.types.d.ts +45 -7
  54. package/dist/{source-provider-j1w7byeq.js → source-provider-3g3yrn1f.js} +2 -2
  55. package/dist/{source-provider-tjaf303m.js → source-provider-azg9ywhb.js} +2 -2
  56. package/dist/{validate-b201dbrb.js → validate-0h3b5vq4.js} +9 -9
  57. package/package.json +1 -1
  58. /package/dist/{cli-y28j019d.js → cli-1dha1nxk.js} +0 -0
@@ -1,5 +1,5 @@
1
1
  import {
2
- BUNDLED_EXTENSIONS,
2
+ BUNDLED_EXTENSION_DETAILS,
3
3
  EXTENSION_MANIFEST_FILENAME,
4
4
  TWO_VERSIONS_OPEN,
5
5
  bundledExtension,
@@ -14,7 +14,7 @@ import {
14
14
  readExtensionMeta,
15
15
  resolveExtension,
16
16
  slugify
17
- } from "./index-80vg3ed6.js";
17
+ } from "./index-37cxffyb.js";
18
18
  import {
19
19
  BuildError,
20
20
  EXIT_CODES,
@@ -32,7 +32,7 @@ import {
32
32
  vendoredNpmPluginRoot,
33
33
  vendoredNpmPluginRoots,
34
34
  windowsPathKey
35
- } from "./index-5x42amh8.js";
35
+ } from "./index-g3te5ey1.js";
36
36
  import {
37
37
  __require
38
38
  } from "./index-37x76zdn.js";
@@ -74,10 +74,10 @@ async function withFetchTimeout(options, run) {
74
74
  }
75
75
 
76
76
  // src/lib/extension-manager.ts
77
- import { readdir, readFile as readFile5, rm as rm3, stat } from "node:fs/promises";
77
+ import { mkdir as mkdir3, readdir, readFile as readFile5, rm as rm3, stat, writeFile as writeFile2 } from "node:fs/promises";
78
78
  import { existsSync as existsSync3 } from "node:fs";
79
79
  import path4 from "node:path";
80
- import { isSeq as isSeq2, isMap, isScalar, YAMLMap, Scalar } from "yaml";
80
+ import { isSeq as isSeq2, isMap as isMap3, isScalar, YAMLMap, Scalar } from "yaml";
81
81
 
82
82
  // src/lib/manifest-doc.ts
83
83
  import { existsSync as existsSync2 } from "node:fs";
@@ -170,7 +170,8 @@ var DTRPG_PRESET = {
170
170
  },
171
171
  validate: {
172
172
  assets: {
173
- maxImageSize: 1e7
173
+ maxImageSize: 1e7,
174
+ approvedFontFiles: []
174
175
  },
175
176
  pdf: {
176
177
  minImageResolution: 300,
@@ -227,7 +228,8 @@ var BOOK_PRESET = {
227
228
  },
228
229
  validate: {
229
230
  assets: {
230
- maxImageSize: 1e7
231
+ maxImageSize: 1e7,
232
+ approvedFontFiles: []
231
233
  },
232
234
  pdf: {
233
235
  minImageResolution: 300,
@@ -387,6 +389,124 @@ function applyDefaultPdfStrictChecks(config) {
387
389
  return next;
388
390
  }
389
391
 
392
+ // src/lib/manifest-old-spellings.ts
393
+ import { isMap as isMap2 } from "yaml";
394
+
395
+ // src/lib/check-options.ts
396
+ import { isMap } from "yaml";
397
+ var CHECK_OPTIONS = {
398
+ "pdf.print.ink-coverage": {
399
+ maxTac: { at: "ink.maxTac", kind: "number" },
400
+ tacTolerance: { at: "ink.tacTolerance", kind: "number" }
401
+ },
402
+ "pdf.print.page-size": {
403
+ tolerance: { at: "page.tolerance", kind: "number" }
404
+ },
405
+ "pdf.print.image-resolution": {
406
+ minImageResolution: { at: "validate.pdf.minImageResolution", kind: "number" }
407
+ },
408
+ "pdf.print.bleed": {
409
+ bleedSize: { at: "validate.pdf.bleedSize", kind: "number" }
410
+ },
411
+ "asset.image.file-size": {
412
+ maxImageSize: { at: "validate.assets.maxImageSize", kind: "number" }
413
+ },
414
+ "asset.font.approved-files": {
415
+ approvedFontFiles: { at: "validate.assets.approvedFontFiles", kind: "patterns" }
416
+ },
417
+ "heuristic.decoration.layer-count": {
418
+ maxDecorativeLayers: { at: "validate.heuristics.maxDecorativeLayers", kind: "number" }
419
+ },
420
+ "heuristic.whitespace.text-density": {
421
+ textDensityRange: { at: "validate.heuristics.textDensityRange", kind: "range" }
422
+ },
423
+ "heuristic.chunking.section-density": {
424
+ maxParagraphsPerSection: { at: "validate.heuristics.maxParagraphsPerSection", kind: "number" }
425
+ }
426
+ };
427
+ function optionForOldSpelling(at) {
428
+ for (const [id, options] of Object.entries(CHECK_OPTIONS)) {
429
+ for (const [option, spec] of Object.entries(options)) {
430
+ if (spec.at === at)
431
+ return { id, option };
432
+ }
433
+ }
434
+ return;
435
+ }
436
+ function isPlainObject(v) {
437
+ return typeof v === "object" && v !== null && !Array.isArray(v);
438
+ }
439
+ var isAmount = (v) => typeof v === "number" && Number.isFinite(v) && v >= 0;
440
+ var isRangeEnd = ([k, v]) => (k === "min" || k === "max") && isAmount(v);
441
+ var MUST_BE = {
442
+ number: "a number, 0 or more",
443
+ range: "`{ min, max }` (numbers, 0 or more)",
444
+ patterns: "a list of file patterns"
445
+ };
446
+ function fits(kind, value) {
447
+ if (kind === "number")
448
+ return isAmount(value);
449
+ if (kind === "range")
450
+ return isPlainObject(value) && Object.entries(value).every(isRangeEnd);
451
+ return Array.isArray(value) && value.every((p) => typeof p === "string");
452
+ }
453
+ function checked(id, option, kind, value) {
454
+ if (fits(kind, value))
455
+ return value;
456
+ throw new UsageError(`Manifest field \`checks.${id}.${option}\` must be ${MUST_BE[kind]}, got ${JSON.stringify(value)}.`);
457
+ }
458
+ function isCheckLevelInput(value) {
459
+ return typeof value === "boolean" || ["off", "on", "info", "warn", "warning", "error"].includes(value);
460
+ }
461
+ function readOldThreshold(at, value) {
462
+ const moved = optionForOldSpelling(at);
463
+ if (!moved)
464
+ return;
465
+ const { kind } = CHECK_OPTIONS[moved.id][moved.option];
466
+ if (fits(kind, value))
467
+ return { ...moved, value };
468
+ const kept = kind === "range" && isPlainObject(value) ? Object.entries(value).filter(isRangeEnd) : [];
469
+ return { ...moved, ...kept.length > 0 ? { value: Object.fromEntries(kept) } : {}, mustBe: MUST_BE[kind] };
470
+ }
471
+ function readCheckOptions(id, entry) {
472
+ const known = CHECK_OPTIONS[id] ?? {};
473
+ const out = {};
474
+ for (const [option, value] of Object.entries(entry)) {
475
+ if (option === "level" || value === null || value === undefined)
476
+ continue;
477
+ const spec = known[option];
478
+ if (!spec) {
479
+ const takes = Object.keys(known);
480
+ throw new UsageError(`Manifest field \`checks.${id}\` has no option \`${option}\`. ` + (takes.length > 0 ? `It takes \`level\` and ${takes.map((o) => `\`${o}\``).join(", ")}.` : "It takes only `level` (off, on, info, warn or error)."));
481
+ }
482
+ out[option] = checked(id, option, spec.kind, value);
483
+ }
484
+ return out;
485
+ }
486
+ function applyCheckOptions(config, options) {
487
+ for (const [id, values] of Object.entries(options)) {
488
+ for (const [option, value] of Object.entries(values)) {
489
+ const spec = CHECK_OPTIONS[id][option];
490
+ const keys = spec.at.split(".");
491
+ const leaf = keys.pop();
492
+ let node = config;
493
+ for (const key of keys)
494
+ node = node[key];
495
+ node[leaf] = spec.kind === "range" ? { ...node[leaf], ...value } : value;
496
+ }
497
+ }
498
+ }
499
+ function setCheckOption(doc, id, option, value) {
500
+ if (!isMap(doc.get("checks", true)))
501
+ doc.set("checks", doc.createNode({}));
502
+ const current = doc.getIn(["checks", id], true);
503
+ if (!isMap(current)) {
504
+ const level = doc.getIn(["checks", id]);
505
+ doc.setIn(["checks", id], doc.createNode(level === undefined || level === null ? {} : { level }));
506
+ }
507
+ doc.setIn(["checks", id, option], value);
508
+ }
509
+
390
510
  // src/lib/manifest-old-spellings.ts
391
511
  var SOURCE_TOOL_CHECKS = {
392
512
  markdownlint: "source.markdownlint",
@@ -405,6 +525,7 @@ var FLAG_CHECKS = {
405
525
  function isObject(v) {
406
526
  return typeof v === "object" && v !== null && !Array.isArray(v);
407
527
  }
528
+ var optionSpelling = (id, option, value) => `checks: { ${id}: { ${option}: ${JSON.stringify(value)} } }`;
408
529
  function readOldSpellings(raw) {
409
530
  const { source, lint, validate, ink, ...manifest } = raw;
410
531
  const tolerance = isObject(raw.page) && "tolerance" in raw.page;
@@ -416,7 +537,32 @@ function readOldSpellings(raw) {
416
537
  }
417
538
  const renamed = [];
418
539
  const dropped = [];
419
- const checks = {};
540
+ const unusable = [];
541
+ const levels = {};
542
+ const options = {};
543
+ const threshold = (at, value) => {
544
+ const read = readOldThreshold(at, value);
545
+ if (!read) {
546
+ dropped.push(at);
547
+ return;
548
+ }
549
+ if (value === null || value === undefined)
550
+ return;
551
+ if (read.value !== undefined) {
552
+ (options[read.id] ??= {})[read.option] = read.value;
553
+ renamed.push(`${at} -> ${optionSpelling(read.id, read.option, read.value)}`);
554
+ }
555
+ if (read.mustBe) {
556
+ const kept = read.value !== undefined ? `kept ${Object.keys(read.value).join(" and ")}, ignored the rest` : "ignored";
557
+ unusable.push(`${at}: ${JSON.stringify(value)} is not ${read.mustBe} — ${kept}`);
558
+ }
559
+ };
560
+ const level = (at, value) => {
561
+ if (isCheckLevelInput(value))
562
+ return value;
563
+ unusable.push(`${at}: ${JSON.stringify(value)} is not off, on, info, warn or error — ignored`);
564
+ return;
565
+ };
420
566
  if (isObject(source) && "files" in source) {
421
567
  renamed.push("source.files -> chapters");
422
568
  if (manifest.chapters === undefined)
@@ -425,18 +571,37 @@ function readOldSpellings(raw) {
425
571
  if (isObject(validate)) {
426
572
  for (const [id, entry] of Object.entries(validate.checks ?? {})) {
427
573
  if (entry === false || isObject(entry) && entry.enabled === false)
428
- checks[id] = "off";
429
- else if (isObject(entry) && typeof entry.severity === "string")
430
- checks[id] = entry.severity;
431
- else
432
- checks[id] = "on";
574
+ levels[id] = "off";
575
+ else if (isObject(entry) && entry.severity !== undefined && entry.severity !== null) {
576
+ levels[id] = level(`validate.checks.${id}.severity`, entry.severity) ?? "on";
577
+ } else
578
+ levels[id] = "on";
433
579
  }
434
580
  if (validate.checks !== undefined)
435
581
  renamed.push("validate.checks -> checks");
582
+ }
583
+ if (isObject(lint)) {
584
+ for (const [id, value] of Object.entries(lint.rules ?? {})) {
585
+ const read = level(`lint.rules.${id}`, value);
586
+ if (read !== undefined)
587
+ levels[id] = read;
588
+ }
589
+ if (lint.rules !== undefined)
590
+ renamed.push("lint.rules -> checks");
591
+ if (lint.enabled === false) {
592
+ levels["source.stylelint"] = "off";
593
+ renamed.push("lint.enabled: false -> checks: { source.stylelint: off }");
594
+ } else if (lint.enabled !== undefined) {
595
+ dropped.push("lint.enabled");
596
+ }
597
+ if (lint.configPath !== undefined)
598
+ dropped.push("lint.configPath");
599
+ }
600
+ if (isObject(validate)) {
436
601
  for (const [tool, value] of Object.entries(validate.source ?? {})) {
437
602
  const id = SOURCE_TOOL_CHECKS[tool];
438
603
  if (id && value === false) {
439
- checks[id] = "off";
604
+ levels[id] = "off";
440
605
  renamed.push(`validate.source.${tool}: false -> checks: { ${id}: off }`);
441
606
  } else if (id && tool !== "stylelint" && typeof value === "string") {
442
607
  dropped.push(`validate.source.${tool} (the config file is found by its usual name in the book's folder or a folder above it)`);
@@ -448,11 +613,14 @@ function readOldSpellings(raw) {
448
613
  for (const [key, value] of Object.entries(validate[block] ?? {})) {
449
614
  const flag = FLAG_CHECKS[`${block}.${key}`];
450
615
  if (flag && typeof value === "boolean") {
451
- const level = value === flag.trueMeansOn ? "on" : "off";
452
- checks[flag.check] = level;
453
- renamed.push(`validate.${block}.${key}: ${value} -> checks: { ${flag.check}: ${level} }`);
616
+ const on = value === flag.trueMeansOn;
617
+ if (!on)
618
+ levels[flag.check] = "off";
619
+ else
620
+ levels[flag.check] ??= "on";
621
+ renamed.push(`validate.${block}.${key}: ${value} -> checks: { ${flag.check}: ${String(levels[flag.check])} }`);
454
622
  } else {
455
- dropped.push(`validate.${block}.${key} (the preset and the publish target set it)`);
623
+ threshold(`validate.${block}.${key}`, value);
456
624
  }
457
625
  }
458
626
  }
@@ -460,32 +628,28 @@ function readOldSpellings(raw) {
460
628
  dropped.push("validate.enabled (`gutterpress build --skip-pre-validate --skip-post-validate` skips validation for one build)");
461
629
  }
462
630
  }
463
- if (isObject(lint)) {
464
- for (const [id, level] of Object.entries(lint.rules ?? {}))
465
- checks[id] = level;
466
- if (lint.rules !== undefined)
467
- renamed.push("lint.rules -> checks");
468
- if (lint.enabled === false) {
469
- checks["source.stylelint"] = "off";
470
- renamed.push("lint.enabled: false -> checks: { source.stylelint: off }");
471
- } else if (lint.enabled !== undefined) {
472
- dropped.push("lint.enabled");
473
- }
474
- if (lint.configPath !== undefined)
475
- dropped.push("lint.configPath");
631
+ if (isObject(ink)) {
632
+ for (const [key, value] of Object.entries(ink))
633
+ threshold(`ink.${key}`, value);
634
+ } else if (ink !== undefined && ink !== null) {
635
+ dropped.push("ink");
476
636
  }
477
- if (ink !== undefined)
478
- dropped.push("ink (the preset and the publish target set it)");
479
637
  if (tolerance) {
480
- const { tolerance: _, ...page } = raw.page;
638
+ const { tolerance: value, ...page } = raw.page;
481
639
  manifest.page = page;
482
- dropped.push("page.tolerance (the preset sets it)");
640
+ threshold("page.tolerance", value);
641
+ }
642
+ const ids = new Set([...Object.keys(levels), ...Object.keys(options)]);
643
+ if (ids.size > 0) {
644
+ const checks = { ...manifest.checks };
645
+ for (const id of ids)
646
+ checks[id] = mergeEntry(levels[id], options[id], manifest.checks?.[id]);
647
+ manifest.checks = checks;
483
648
  }
484
- if (Object.keys(checks).length > 0)
485
- manifest.checks = { ...checks, ...manifest.checks };
486
649
  const lines = [
487
650
  ...renamed.map((r) => ` ${r}`),
488
- ...dropped.map((d) => ` ${d} — no longer a setting, ignored`)
651
+ ...dropped.map((d) => ` ${d} — no longer a setting, ignored`),
652
+ ...unusable.map((u) => ` ${u}`)
489
653
  ];
490
654
  if (lines.length > 0) {
491
655
  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:
@@ -494,6 +658,43 @@ function readOldSpellings(raw) {
494
658
  }
495
659
  return manifest;
496
660
  }
661
+ function mergeEntry(level, options, own) {
662
+ const ownEntry = isObject(own) ? own : own === undefined ? {} : { level: own };
663
+ const merged = {
664
+ ...level !== undefined ? { level } : {},
665
+ ...options,
666
+ ...ownEntry
667
+ };
668
+ if (ownEntry.level === undefined && level !== undefined)
669
+ merged.level = level;
670
+ const keys = Object.keys(merged);
671
+ return keys.length === 1 && keys[0] === "level" ? merged.level : merged;
672
+ }
673
+ function rewriteOldThresholds(doc) {
674
+ const blocks = [["ink"], ["page"], ["validate", "assets"], ["validate", "pdf"], ["validate", "heuristics"]];
675
+ for (const block of blocks) {
676
+ const node = doc.getIn(block, true);
677
+ if (!isMap2(node))
678
+ continue;
679
+ for (const item of [...node.items]) {
680
+ const key = String(item.key?.value ?? item.key);
681
+ const value = item.value;
682
+ const js = value && typeof value === "object" && "toJSON" in value ? value.toJSON() : value;
683
+ const read = readOldThreshold([...block, key].join("."), js);
684
+ if (!read || js !== null && js !== undefined && read.mustBe)
685
+ continue;
686
+ if (js !== null && js !== undefined && doc.getIn(["checks", read.id, read.option]) === undefined) {
687
+ setCheckOption(doc, read.id, read.option, value);
688
+ }
689
+ node.delete(key);
690
+ }
691
+ }
692
+ for (const block of [...blocks, ["validate"]]) {
693
+ const node = doc.getIn(block, true);
694
+ if (isMap2(node) && node.items.length === 0)
695
+ doc.deleteIn(block);
696
+ }
697
+ }
497
698
 
498
699
  // src/lib/manifest.ts
499
700
  var MANIFEST_FILENAMES = [
@@ -612,7 +813,7 @@ function pluginsRemovedMessage(raw) {
612
813
  ` + (lines.length > 0 ? lines.join(`
613
814
  `) : " - ./plugins/my-plugin.js");
614
815
  }
615
- function isPlainObject(v) {
816
+ function isPlainObject2(v) {
616
817
  return typeof v === "object" && v !== null && !Array.isArray(v);
617
818
  }
618
819
  function mergeShape(cli, manifest, preset) {
@@ -621,7 +822,7 @@ function mergeShape(cli, manifest, preset) {
621
822
  const presetValue = preset[key];
622
823
  const manifestValue = manifest ? manifest[key] : undefined;
623
824
  const cliValue = cli ? cli[key] : undefined;
624
- out[key] = isPlainObject(presetValue) ? mergeShape(cliValue, manifestValue, presetValue) : cliValue ?? manifestValue ?? presetValue;
825
+ out[key] = isPlainObject2(presetValue) ? mergeShape(cliValue, manifestValue, presetValue) : cliValue ?? manifestValue ?? presetValue;
625
826
  }
626
827
  return out;
627
828
  }
@@ -669,7 +870,7 @@ function resolveCustomPage(c, m) {
669
870
  }
670
871
  var MARGIN_EDGES = ["top", "bottom", "inside", "outside"];
671
872
  function validatePageMargin(margin, size) {
672
- const edges = isPlainObject(margin) && Object.keys(margin).every((k) => MARGIN_EDGES.includes(k)) && MARGIN_EDGES.every((e) => isNonNegativePoints(margin[e]));
873
+ const edges = isPlainObject2(margin) && Object.keys(margin).every((k) => MARGIN_EDGES.includes(k)) && MARGIN_EDGES.every((e) => isNonNegativePoints(margin[e]));
673
874
  if (!edges) {
674
875
  throw new UsageError("Manifest field `page.margin` must set all four edges in points (72pt = 1in), for example\n" + ` page:
675
876
  margin:
@@ -726,7 +927,9 @@ function resolveWithPreset(cliOverrides, manifest, preset) {
726
927
  const page = preset.page ? mergeShape(c.page, m.page, preset.page) : resolveCustomPage(c, m);
727
928
  if (page.margin !== undefined && page.margin !== null)
728
929
  validatePageMargin(page.margin, page);
729
- return {
930
+ const manifestChecks = resolveChecks(m.checks);
931
+ const cliChecks = resolveChecks(c.checks);
932
+ const config = {
730
933
  title: c.title ?? m.title ?? "Document",
731
934
  authors: c.authors ?? m.authors ?? [],
732
935
  language: resolveLanguage(c.language ?? m.language),
@@ -736,35 +939,47 @@ function resolveWithPreset(cliOverrides, manifest, preset) {
736
939
  extensions,
737
940
  targets: resolveTargets(c.targets ?? m.targets, preset.defaultTargets),
738
941
  chapters: c.chapters ?? m.chapters ?? preset.chapters,
739
- checks: { ...preset.checks, ...resolveCheckLevels(m.checks), ...resolveCheckLevels(c.checks) },
942
+ checks: { ...preset.checks, ...manifestChecks.levels, ...cliChecks.levels },
740
943
  pdfx: mergeShape(c.pdfx, m.pdfx, preset.pdfx),
741
944
  print: mergeShape(c.print, m.print, preset.print),
742
945
  page,
743
946
  ink: structuredClone(preset.ink),
744
947
  validate: structuredClone(preset.validate)
745
948
  };
746
- }
747
- function resolveCheckLevels(input) {
949
+ applyCheckOptions(config, manifestChecks.options);
950
+ applyCheckOptions(config, cliChecks.options);
951
+ return config;
952
+ }
953
+ function checkLevel(id, value) {
954
+ if (!isCheckLevelInput(value)) {
955
+ throw new UsageError(`Manifest field \`checks.${id}\` must be off, on, info, warn or error, got ${JSON.stringify(value)}.`);
956
+ }
957
+ if (value === false || value === "off")
958
+ return "off";
959
+ if (value === true || value === "on")
960
+ return "on";
961
+ return value === "warn" || value === "warning" ? "warning" : value;
962
+ }
963
+ function resolveChecks(input) {
964
+ const levels = {};
965
+ const options = {};
748
966
  if (input === undefined || input === null)
749
- return {};
750
- if (!isPlainObject(input)) {
967
+ return { levels, options };
968
+ if (!isPlainObject2(input)) {
751
969
  throw new UsageError("Manifest field `checks` must map check ids to off, on, info, warn or error.");
752
970
  }
753
- const out = {};
754
971
  for (const [id, value] of Object.entries(input)) {
755
- if (value === false || value === "off")
756
- out[id] = "off";
757
- else if (value === true || value === "on")
758
- out[id] = "on";
759
- else if (value === "warn" || value === "warning")
760
- out[id] = "warning";
761
- else if (value === "info" || value === "error")
762
- out[id] = value;
763
- else {
764
- throw new UsageError(`Manifest field \`checks.${id}\` must be off, on, info, warn or error, got ${JSON.stringify(value)}.`);
972
+ if (!isPlainObject2(value)) {
973
+ levels[id] = checkLevel(id, value);
974
+ continue;
765
975
  }
976
+ if (value.level !== undefined && value.level !== null)
977
+ levels[id] = checkLevel(`${id}.level`, value.level);
978
+ const own = readCheckOptions(id, value);
979
+ if (Object.keys(own).length > 0)
980
+ options[id] = own;
766
981
  }
767
- return out;
982
+ return { levels, options };
768
983
  }
769
984
 
770
985
  // src/lib/manifest-doc.ts
@@ -1544,7 +1759,7 @@ function withMutationLock(projectDir, mutation) {
1544
1759
  function entryUse(item) {
1545
1760
  if (isScalar(item))
1546
1761
  return typeof item.value === "string" ? item.value.trim() : null;
1547
- if (isMap(item)) {
1762
+ if (isMap3(item)) {
1548
1763
  const u = item.get("use");
1549
1764
  return typeof u === "string" ? u.trim() : null;
1550
1765
  }
@@ -1554,7 +1769,7 @@ function rawEntry(item) {
1554
1769
  const use = entryUse(item);
1555
1770
  if (!use)
1556
1771
  return null;
1557
- if (!isMap(item))
1772
+ if (!isMap3(item))
1558
1773
  return { use, enabled: true };
1559
1774
  const x = item.get("export");
1560
1775
  return {
@@ -1727,13 +1942,13 @@ async function setExtensionEnabled(projectDir, use, enabled) {
1727
1942
  throw new Error(`Extension "${use}" is not in the manifest.`);
1728
1943
  const item = seq.items[idx];
1729
1944
  if (enabled) {
1730
- if (isMap(item)) {
1945
+ if (isMap3(item)) {
1731
1946
  item.delete("enabled");
1732
1947
  if (item.items.length === 1 && typeof item.get("use") === "string") {
1733
1948
  seq.items[idx] = new Scalar(item.get("use"));
1734
1949
  }
1735
1950
  }
1736
- } else if (isMap(item)) {
1951
+ } else if (isMap3(item)) {
1737
1952
  item.set("enabled", false);
1738
1953
  } else {
1739
1954
  const map = new YAMLMap(doc.schema);
@@ -1799,7 +2014,7 @@ async function upsertEntry(projectDir, use, exportName) {
1799
2014
  const idx = indexOfUse(seq, use);
1800
2015
  if (idx >= 0) {
1801
2016
  const item = seq.items[idx];
1802
- if (isMap(item)) {
2017
+ if (isMap3(item)) {
1803
2018
  item.set("use", use);
1804
2019
  if (exportName)
1805
2020
  item.set("export", exportName);
@@ -2060,13 +2275,53 @@ async function updateExtensions(projectDir, options = {}) {
2060
2275
  return updated;
2061
2276
  }
2062
2277
  function listBundledExtensions() {
2063
- return BUNDLED_EXTENSIONS.map((b) => ({
2278
+ return BUNDLED_EXTENSION_DETAILS.map((b) => ({
2064
2279
  use: b.name,
2065
2280
  label: b.label,
2066
2281
  description: b.description,
2067
2282
  look: b.css !== undefined
2068
2283
  }));
2069
2284
  }
2285
+ var BUILT_IN_LOOKS = BUNDLED_EXTENSION_DETAILS.filter((b) => b.css !== undefined).map((b) => b.name);
2286
+ async function addBuiltInStyleSet(projectDir, id) {
2287
+ const look = bundledExtension(id);
2288
+ if (look?.css === undefined) {
2289
+ throw new Error(`Unknown built-in look "${id}" (one of: ${BUILT_IN_LOOKS.join(", ")}).`);
2290
+ }
2291
+ const css = look.css;
2292
+ return withMutationLock(projectDir, async () => {
2293
+ const dest = path4.join(projectDir, EXTENSIONS_DIR, id);
2294
+ if (!existsSync3(dest)) {
2295
+ await mkdir3(dest, { recursive: true });
2296
+ const pkg = {
2297
+ name: id,
2298
+ description: look.description,
2299
+ author: "gutterpress",
2300
+ keywords: ["gutterpress", "gutterpress-look"],
2301
+ gutterpress: { styles: ["theme.css"] }
2302
+ };
2303
+ await writeFile2(path4.join(dest, EXTENSION_MANIFEST_FILENAME), `${JSON.stringify(pkg, null, 2)}
2304
+ `, "utf8");
2305
+ await writeFile2(path4.join(dest, "theme.css"), css, "utf8");
2306
+ }
2307
+ const use = `./${EXTENSIONS_DIR}/${id}`;
2308
+ await loadPlugin(extensionConfigFor({ use, kind: "path", name: use }), projectDir);
2309
+ const { doc, file } = await loadManifestDoc(projectDir);
2310
+ const seq = ensureSeq(doc, "extensions");
2311
+ if (indexOfUse(seq, use) < 0) {
2312
+ const at = indexOfUse(seq, id);
2313
+ const item = at < 0 ? undefined : seq.items[at];
2314
+ if (isMap3(item))
2315
+ item.set("use", use);
2316
+ else if (at >= 0)
2317
+ seq.items[at] = new Scalar(use);
2318
+ else
2319
+ seq.add(new Scalar(use));
2320
+ await writeManifestDoc(file, doc);
2321
+ }
2322
+ return await describeExtension(projectDir, use);
2323
+ });
2324
+ }
2070
2325
  async function uniqueExtensionId(projectDir, base) {
2071
2326
  const slug = slugify(base) || "extension";
2072
2327
  let candidate = slug;
@@ -2238,4 +2493,4 @@ async function restoreForCommand(dir, options) {
2238
2493
  log.warn(problem);
2239
2494
  }
2240
2495
 
2241
- export { DEBOUNCE, UsageError, resolvePort, PRESET_IDS, PRESETS, TARGETS, TARGET_IDS, publishTargetFor, resolveTargets, applyDefaultPdfStrictChecks, MANIFEST_FILENAMES, hasProjectManifest, loadManifest, loadManifestWithPath, resolveConfig, resolveConfigForTarget, MARGIN_EDGES, validatePageMargin, FriendlyHttpError, withFetchTimeout, loadManifestDoc, writeManifestDoc, scalarString, DEFAULT_NPM_REGISTRY, npmRegistryUrl, ensureProjectGitignore, sameExtension, listProjectExtensions, describeExtension, extensionConfigFor, setExtensionEnabled, reorderExtensions, removeExtension, addExtension, listNpmVersions, checkExtensionUpdates, updateExtensions, listBundledExtensions, uniqueExtensionId, validateProjectExtensions, readExtensionCss, readEntryCss, restorePinnedExtensions, restoreFailureMessage, restoreOfflineMessage, restoreForCommand };
2496
+ export { DEBOUNCE, UsageError, resolvePort, PRESET_IDS, PRESETS, TARGETS, TARGET_IDS, publishTargetFor, resolveTargets, applyDefaultPdfStrictChecks, setCheckOption, rewriteOldThresholds, MANIFEST_FILENAMES, hasProjectManifest, loadManifest, loadManifestWithPath, resolveConfig, resolveConfigForTarget, MARGIN_EDGES, validatePageMargin, FriendlyHttpError, withFetchTimeout, loadManifestDoc, writeManifestDoc, scalarString, DEFAULT_NPM_REGISTRY, npmRegistryUrl, ensureProjectGitignore, sameExtension, listProjectExtensions, describeExtension, extensionConfigFor, setExtensionEnabled, reorderExtensions, removeExtension, addExtension, listNpmVersions, checkExtensionUpdates, updateExtensions, listBundledExtensions, BUILT_IN_LOOKS, addBuiltInStyleSet, uniqueExtensionId, validateProjectExtensions, readExtensionCss, readEntryCss, restorePinnedExtensions, restoreFailureMessage, restoreOfflineMessage, restoreForCommand };
@@ -697,7 +697,7 @@ import { fileURLToPath } from "node:url";
697
697
  var favicon_default = "./favicon-272ga6y0.ico";
698
698
 
699
699
  // src/assets/manifest.schema.json
700
- var manifest_schema_default = "./manifest.schema-0jgj0jt1.json";
700
+ var manifest_schema_default = "./manifest.schema-5cm13vr3.json";
701
701
 
702
702
  // src/assets/preview/scripts/preview-interface.js
703
703
  var preview_interface_default = "./preview-interface-0xdh0r5b.js";
@@ -3,6 +3,7 @@ import { lstat, readFile, realpath } from "node:fs/promises";
3
3
  import path from "node:path";
4
4
  import { exports as resolveExports } from "resolve.exports";
5
5
  var EXTENSIONS_DIR = "extensions";
6
+ var PLUGINS_DIR = EXTENSIONS_DIR;
6
7
  var LEGACY_PLUGINS_DIR = "plugins";
7
8
  var VENDORED_NPM_DIR = "npm";
8
9
  var NPM_SEGMENT = /^[a-z0-9][a-z0-9._~-]*$/;
@@ -206,4 +207,4 @@ async function resolveVendoredPluginInstallRoot(projectDir, expectedName, expect
206
207
  return installRoot;
207
208
  }
208
209
 
209
- export { EXTENSIONS_DIR, LEGACY_PLUGINS_DIR, VENDORED_NPM_DIR, isValidNpmPackageName, parseNpmPluginSpec, isExactNpmVersion, vendoredNpmPluginRoot, vendoredNpmPluginRoots, vendoredNpmPluginPackageDir, toPosixPath, assertWindowsSafeRelativePath, windowsPathKey, packageResolutionTargets, safePackageTarget, resolvePackageEntry, resolveVendoredPluginInstallRoot };
210
+ export { EXTENSIONS_DIR, PLUGINS_DIR, LEGACY_PLUGINS_DIR, VENDORED_NPM_DIR, isValidNpmPackageName, parseNpmPluginSpec, isExactNpmVersion, vendoredNpmPluginRoot, vendoredNpmPluginRoots, vendoredNpmPluginPackageDir, toPosixPath, assertWindowsSafeRelativePath, windowsPathKey, packageResolutionTargets, safePackageTarget, resolvePackageEntry, resolveVendoredPluginInstallRoot };
@@ -2,7 +2,7 @@ import {
2
2
  EXTENSIONS_DIR,
3
3
  LEGACY_PLUGINS_DIR,
4
4
  VENDORED_NPM_DIR
5
- } from "./index-5x42amh8.js";
5
+ } from "./index-g3te5ey1.js";
6
6
  import {
7
7
  capabilitiesFor,
8
8
  detectProjectSource,