@heroiclands/package-build 8.0.0 → 9.0.0

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/CHANGELOG.md +173 -0
  2. package/bin/content-build.mjs +44 -118
  3. package/bin/package-build.mjs +27 -69
  4. package/bin/report.mjs +1 -2
  5. package/bundle.mjs +2 -10
  6. package/config.mjs +31 -106
  7. package/container.mjs +13 -57
  8. package/content-config.mjs +45 -164
  9. package/coverage.mjs +14 -55
  10. package/deploy.mjs +4 -13
  11. package/e2e.mjs +16 -55
  12. package/engine/address-diff.mjs +1 -4
  13. package/engine/base-compiler.mjs +10 -28
  14. package/engine/code-fences.mjs +4 -13
  15. package/engine/compendiums.mjs +13 -37
  16. package/engine/content-address.mjs +2 -6
  17. package/engine/content-links.mjs +13 -44
  18. package/engine/content-lint.mjs +4 -15
  19. package/engine/content-slug.mjs +2 -6
  20. package/engine/content-tables.mjs +26 -79
  21. package/engine/diagnostics.mjs +4 -15
  22. package/engine/field-reference.mjs +6 -20
  23. package/engine/field-spec.mjs +1 -3
  24. package/engine/foreign-catalog.mjs +7 -22
  25. package/engine/foreign-manifests.mjs +1 -4
  26. package/engine/frontmatter-lint.mjs +6 -18
  27. package/engine/frontmatter.mjs +3 -8
  28. package/engine/generate.mjs +4 -16
  29. package/engine/helpers.mjs +13 -52
  30. package/engine/homepage.mjs +4 -15
  31. package/engine/ids.mjs +3 -12
  32. package/engine/item-registry.mjs +2 -6
  33. package/engine/journals.mjs +4 -14
  34. package/engine/kb-manifest.mjs +5 -17
  35. package/engine/macros.mjs +2 -10
  36. package/engine/manifest-emit.mjs +6 -17
  37. package/engine/map-notes.mjs +19 -69
  38. package/engine/note-package.mjs +1 -4
  39. package/engine/pack-config.mjs +17 -38
  40. package/engine/pack-router.mjs +1 -2
  41. package/engine/prose-config.mjs +20 -4
  42. package/engine/prose-lint.mjs +6 -14
  43. package/engine/region-events.mjs +1 -3
  44. package/engine/scene-levels.mjs +8 -22
  45. package/engine/scenes.mjs +13 -47
  46. package/engine/schema-check.mjs +1 -4
  47. package/engine/schema-extract.mjs +70 -45
  48. package/engine/site-build.mjs +12 -37
  49. package/engine/site-index.mjs +3 -15
  50. package/engine/web-wikilinks.mjs +4 -13
  51. package/engine/wikilinks.mjs +115 -167
  52. package/index.mjs +1 -5
  53. package/lang.mjs +1 -3
  54. package/manifest.mjs +10 -37
  55. package/markdownlint-config.mjs +1 -5
  56. package/package.json +1 -1
  57. package/sohl/actors.mjs +10 -40
  58. package/sohl/being-info.mjs +3 -6
  59. package/sohl/index.mjs +1 -6
  60. package/sohl/item-builders.mjs +1 -3
  61. package/sohl/item-fields.mjs +16 -34
  62. package/sohl/items.mjs +1 -3
  63. package/sohl/kb-passes.mjs +29 -39
  64. package/sohl/skill-base.mjs +7 -23
  65. package/stage.mjs +3 -13
  66. package/templates.mjs +4 -15
  67. package/types/bundle.d.mts +1 -1
  68. package/types/container.d.mts +2 -2
  69. package/types/coverage.d.mts +1 -1
  70. package/types/e2e.d.mts +4 -4
  71. package/types/engine/generate.d.mts +1 -1
  72. package/types/engine/helpers.d.mts +1 -1
  73. package/types/engine/schema-extract.d.mts +1 -1
  74. package/types/engine/site-index.d.mts +1 -1
  75. package/types/manifest.d.mts +1 -1
@@ -89,9 +89,7 @@ import { draftRetiredMessage } from "./retired-fields.mjs";
89
89
  *
90
90
  * @type {ReadonlySet<string>}
91
91
  */
92
- export const UNIVERSAL_KEYS = Object.freeze(
93
- new Set(["folder", "pack", "archetype", "kbcat"]),
94
- );
92
+ export const UNIVERSAL_KEYS = Object.freeze(new Set(["folder", "pack", "archetype", "kbcat"]));
95
93
 
96
94
  /**
97
95
  * Edit distance, capped — enough to answer "did you mean".
@@ -166,11 +164,7 @@ export function matchesKind(value, kind) {
166
164
  value.trim() !== "" &&
167
165
  Number.isFinite(Number(value));
168
166
  case "boolean":
169
- return (
170
- typeof value === "boolean" ||
171
- value === "true" ||
172
- value === "false"
173
- );
167
+ return typeof value === "boolean" || value === "true" || value === "false";
174
168
  case "string":
175
169
  return typeof value !== "object" || value === null;
176
170
  case "list":
@@ -179,9 +173,7 @@ export function matchesKind(value, kind) {
179
173
  // An emptied map arrives as `[]` from the property editor, and
180
174
  // means "this note authors no entries" — the same thing `{}` means.
181
175
  return (
182
- (typeof value === "object" &&
183
- value !== null &&
184
- !Array.isArray(value)) ||
176
+ (typeof value === "object" && value !== null && !Array.isArray(value)) ||
185
177
  (Array.isArray(value) && value.length === 0)
186
178
  );
187
179
  default:
@@ -197,9 +189,7 @@ export function matchesKind(value, kind) {
197
189
  */
198
190
  function sohlBlock(fm) {
199
191
  const block = fm?.sohl;
200
- return block && typeof block === "object" && !Array.isArray(block) ?
201
- block
202
- : {};
192
+ return block && typeof block === "object" && !Array.isArray(block) ? block : {};
203
193
  }
204
194
 
205
195
  /**
@@ -217,8 +207,7 @@ export function lintNote(note, { schemas, index }) {
217
207
  const fm = note.fm ?? {};
218
208
  const type = String(fm.type ?? "");
219
209
  const raw = () => note.raw ?? "";
220
- const at = (key, literal) =>
221
- positionInFrontmatter(raw(), key, literal ?? undefined);
210
+ const at = (key, literal) => positionInFrontmatter(raw(), key, literal ?? undefined);
222
211
 
223
212
  // The retired top-level fields, checked before the type: a note may carry
224
213
  // one whatever its type is, and each finding stands on its own. Reported
@@ -312,8 +301,7 @@ export function lintNote(note, { schemas, index }) {
312
301
  const [head, ...rest] = field.name.split(".");
313
302
  let value = block[head];
314
303
  for (const segment of rest) {
315
- value =
316
- value && typeof value === "object" ? value[segment] : undefined;
304
+ value = value && typeof value === "object" ? value[segment] : undefined;
317
305
  }
318
306
  const absent = value === undefined || value === null;
319
307
 
@@ -119,8 +119,7 @@ export function resolveCharges(fm) {
119
119
  // A blank maximum means "does not use charges" — a stray current count
120
120
  // cannot outlive it, since the logic layer disables both modifiers.
121
121
  return {
122
- value:
123
- max === null ? null : toCount(sohlField(fm, "charges.value", null)),
122
+ value: max === null ? null : toCount(sohlField(fm, "charges.value", null)),
124
123
  max,
125
124
  };
126
125
  }
@@ -149,9 +148,7 @@ export function resolveCharges(fm) {
149
148
  export function resolveSkillAptitudes(fm, ctx = "item") {
150
149
  const entries = readMapEntries(fm, "skillAptitudes");
151
150
  if (entries === null) {
152
- throw new Error(
153
- `${ctx}: skillAptitudes must be a map of selector → number`,
154
- );
151
+ throw new Error(`${ctx}: skillAptitudes must be a map of selector → number`);
155
152
  }
156
153
  const out = {};
157
154
  for (const [selector, value] of entries) {
@@ -187,9 +184,7 @@ export function resolveSkillAptitudes(fm, ctx = "item") {
187
184
  export function resolveRelation(fm, ctx = "item") {
188
185
  const entries = readMapEntries(fm, "relation");
189
186
  if (entries === null) {
190
- throw new Error(
191
- `${ctx}: relation must be a map of shortcode → standing`,
192
- );
187
+ throw new Error(`${ctx}: relation must be a map of shortcode → standing`);
193
188
  }
194
189
  const out = {};
195
190
  for (const [code, value] of entries) {
@@ -48,12 +48,7 @@ import { Journals } from "./journals.mjs";
48
48
  import { Actors } from "../sohl/actors.mjs";
49
49
  import { Macros } from "./macros.mjs";
50
50
  import { Scenes } from "./scenes.mjs";
51
- import {
52
- statsForPack,
53
- loadFolders,
54
- buildFolderResolver,
55
- writeFolderDocs,
56
- } from "./helpers.mjs";
51
+ import { statsForPack, loadFolders, buildFolderResolver, writeFolderDocs } from "./helpers.mjs";
57
52
  import { countContentNotes } from "./content-tree.mjs";
58
53
  import { emitDiagnostic } from "./diagnostics.mjs";
59
54
  import { loadPackConfig } from "./pack-config.mjs";
@@ -170,10 +165,7 @@ export function orderPassesByDependency(packs) {
170
165
  readsOutputOf(pack.type).every(
171
166
  (dependency) =>
172
167
  !declared.has(dependency) ||
173
- packs.every(
174
- (other) =>
175
- other.type !== dependency || emitted.has(other.name),
176
- ),
168
+ packs.every((other) => other.type !== dependency || emitted.has(other.name)),
177
169
  );
178
170
 
179
171
  while (remaining.length) {
@@ -269,8 +261,7 @@ async function generatePack(
269
261
  let folderList;
270
262
  let resolver;
271
263
  try {
272
- folderList =
273
- folders ? loadFolders(path.join(contentBase, folders)) : [];
264
+ folderList = folders ? loadFolders(path.join(contentBase, folders)) : [];
274
265
  ({ resolver } = buildFolderResolver(folderList));
275
266
  } catch (err) {
276
267
  log.error(`${name} ${folders} validation failed: ${err.message}`);
@@ -365,10 +356,7 @@ export function emptyPassErrors(passes) {
365
356
  * @throws {Error} If the configured Foundry package id has drifted from the
366
357
  * shipped manifest's `id` (see `package-manifest.mjs`).
367
358
  */
368
- export async function generatePacksJson({
369
- only,
370
- config = loadPackConfig(),
371
- } = {}) {
359
+ export async function generatePacksJson({ only, config = loadPackConfig() } = {}) {
372
360
  // Before anything is generated: every UUID written below is addressed to
373
361
  // the configured `foundryPackage`, so a value that has drifted from the shipped
374
362
  // manifest's `id` produces a whole pack of links that resolve nowhere.
@@ -89,8 +89,7 @@ export function parseMarkdownFile(filePath) {
89
89
  // be reported as a file position (#17). The frontmatter's lines and the
90
90
  // blank lines `trim()` removes both sit in between, and the trim can take
91
91
  // indentation off the first line as well — hence a column, not just a line.
92
- const bodyStart =
93
- content.length - raw.length + (raw.length - raw.trimStart().length);
92
+ const bodyStart = content.length - raw.length + (raw.length - raw.trimStart().length);
94
93
  const before = content.slice(0, bodyStart);
95
94
  const bodyLine = before.split("\n").length;
96
95
  const bodyColumn = bodyStart - before.lastIndexOf("\n");
@@ -321,10 +320,7 @@ export function supportedCoreVersion(config = loadPackConfig()) {
321
320
  * The resolved build configuration. Defaults to this repository's.
322
321
  * @returns {object} The `_stats` block.
323
322
  */
324
- export function buildStats(
325
- systemVersion = undefined,
326
- config = loadPackConfig(),
327
- ) {
323
+ export function buildStats(systemVersion = undefined, config = loadPackConfig()) {
328
324
  return {
329
325
  systemId: config.stats.systemId,
330
326
  systemVersion: systemVersion ?? config.stats.systemVersion,
@@ -473,9 +469,7 @@ export function buildContentLinkIndex(contentBase, router = packRouter()) {
473
469
  );
474
470
  if (stale.length) {
475
471
  for (const st of stale) {
476
- log.error(
477
- `Unusable link manifest for "${st.package}": ${st.reason}`,
478
- );
472
+ log.error(`Unusable link manifest for "${st.package}": ${st.reason}`);
479
473
  }
480
474
  throw new Error(
481
475
  "Cross-package links cannot be resolved from a stale manifest; " +
@@ -486,12 +480,7 @@ export function buildContentLinkIndex(contentBase, router = packRouter()) {
486
480
  `Wikilink index: ${docs.length} local document(s), ` +
487
481
  `${foreign.size} foreign address(es)`,
488
482
  );
489
- return buildWikilinkIndex(
490
- docs,
491
- foundryPackageId(),
492
- foreign,
493
- contentPackage(),
494
- );
483
+ return buildWikilinkIndex(docs, foundryPackageId(), foreign, contentPackage());
495
484
  }
496
485
 
497
486
  /**
@@ -518,18 +507,7 @@ export function buildContentLinkIndex(contentBase, router = packRouter()) {
518
507
  */
519
508
  export function convertNoteWikilinks(
520
509
  body,
521
- {
522
- type,
523
- id,
524
- pack,
525
- docPack,
526
- index,
527
- name,
528
- file,
529
- bodyLine,
530
- bodyColumn,
531
- lineMap,
532
- },
510
+ { type, id, pack, docPack, index, name, file, bodyLine, bodyColumn, lineMap },
533
511
  ) {
534
512
  const result = convertWikilinks(body ?? "", {
535
513
  type,
@@ -580,9 +558,7 @@ export function convertNoteWikilinks(
580
558
  const claims = u.candidates ?? [];
581
559
  const named =
582
560
  claims.length ?
583
- claims
584
- .map((c) => `"${c.name}" (${c.type}-${c.shortcode})`)
585
- .join(" and ")
561
+ claims.map((c) => `"${c.name}" (${c.type}-${c.shortcode})`).join(" and ")
586
562
  : "two or more notes";
587
563
  fail(
588
564
  u,
@@ -613,9 +589,7 @@ export function convertNoteWikilinks(
613
589
  `unresolved wikilink ${u.link} (${u.reason}) in "${name}"` +
614
590
  // A link this build wrote is not at any authored position, so
615
591
  // say where it came from instead of implying an edit site.
616
- (at.generated ?
617
- " — emitted by the content table on this line"
618
- : ""),
592
+ (at.generated ? " — emitted by the content table on this line" : ""),
619
593
  });
620
594
  }
621
595
  return result;
@@ -668,8 +642,7 @@ export function collectContentDocs(contentBase) {
668
642
  * unlinkable; a note missing either renders as plain text rather than shipping a
669
643
  * literal wikilink into a journal.
670
644
  */
671
- const packLinkable = (doc) =>
672
- Boolean(doc.fm?.shortcode) && Boolean(doc.fm?.type);
645
+ const packLinkable = (doc) => Boolean(doc.fm?.shortcode) && Boolean(doc.fm?.type);
673
646
 
674
647
  /**
675
648
  * Expand the fenced `dataview` tables in one note's markdown, before wikilinks
@@ -710,9 +683,7 @@ export function expandNoteTables(body, { docs, name, fm, bodyLine }) {
710
683
  self,
711
684
  });
712
685
  if (errors.length) {
713
- const err = new Error(
714
- errors.map((e) => `content table — ${e.reason}`).join("; "),
715
- );
686
+ const err = new Error(errors.map((e) => `content table — ${e.reason}`).join("; "));
716
687
  // The first failing directive's line. Reporting one position for a
717
688
  // message that may name several is honest here: a caller opens the
718
689
  // file at the first thing to fix, and the message lists the rest.
@@ -735,18 +706,14 @@ export function expandNoteTables(body, { docs, name, fm, bodyLine }) {
735
706
  */
736
707
  export function loadFolders(foldersFile) {
737
708
  if (!fs.existsSync(foldersFile)) {
738
- log.warn(
739
- `No folders.yaml at ${foldersFile}; no folders will be emitted`,
740
- );
709
+ log.warn(`No folders.yaml at ${foldersFile}; no folders will be emitted`);
741
710
  return [];
742
711
  }
743
712
  const raw = fs.readFileSync(foldersFile, "utf8");
744
713
  const parsed = yaml.parse(raw);
745
714
  if (parsed == null) return [];
746
715
  if (!Array.isArray(parsed)) {
747
- throw new Error(
748
- `folders.yaml must contain a YAML list; got ${typeof parsed}`,
749
- );
716
+ throw new Error(`folders.yaml must contain a YAML list; got ${typeof parsed}`);
750
717
  }
751
718
  return parsed;
752
719
  }
@@ -818,10 +785,7 @@ export function buildFolderResolver(folders) {
818
785
  * underscores.
819
786
  */
820
787
  export function folderFilename(name, id) {
821
- return (
822
- `folder_${unidecode(name)}_${id}`.replace(/[^0-9a-zA-Z]+/g, "_") +
823
- ".json"
824
- );
788
+ return `folder_${unidecode(name)}_${id}`.replace(/[^0-9a-zA-Z]+/g, "_") + ".json";
825
789
  }
826
790
 
827
791
  /**
@@ -843,10 +807,7 @@ export function writeFolderDocs(folders, stats, destDir, documentType) {
843
807
  _stats: stats,
844
808
  _key: `!folders!${folder.id}`,
845
809
  };
846
- const outPath = path.join(
847
- destDir,
848
- folderFilename(folder.name, folder.id),
849
- );
810
+ const outPath = path.join(destDir, folderFilename(folder.name, folder.id));
850
811
  fs.writeFileSync(outPath, JSON.stringify(doc, null, 2), "utf8");
851
812
  }
852
813
  log.info(`Emitted ${folders.length} folder document(s) to ${destDir}`);
@@ -262,9 +262,7 @@ export function checkHomepageCount(found, { contentBase, contentPackage }) {
262
262
  if (pages.length === 1) return [];
263
263
 
264
264
  return pages.map((page) => {
265
- const others = pages
266
- .filter((p) => p !== page)
267
- .map((p) => formatLocator({ file: p.file }));
265
+ const others = pages.filter((p) => p !== page).map((p) => formatLocator({ file: p.file }));
268
266
  return {
269
267
  file: page.file,
270
268
  ...positionOfType(page.file),
@@ -292,11 +290,7 @@ export function checkHomepageCount(found, { contentBase, contentPackage }) {
292
290
  */
293
291
  function positionOfType(file) {
294
292
  try {
295
- return positionInFrontmatter(
296
- fs.readFileSync(file, "utf8"),
297
- "type",
298
- HOMEPAGE_TYPE,
299
- );
293
+ return positionInFrontmatter(fs.readFileSync(file, "utf8"), "type", HOMEPAGE_TYPE);
300
294
  } catch {
301
295
  return {};
302
296
  }
@@ -325,9 +319,7 @@ export function homepageTitle(fm, config) {
325
319
  config?.packageBuild?.manifest
326
320
  );
327
321
  const title = manifest?.title;
328
- return typeof title === "string" && title.trim() ?
329
- title
330
- : config.contentPackage;
322
+ return typeof title === "string" && title.trim() ? title : config.contentPackage;
331
323
  }
332
324
 
333
325
  /**
@@ -394,10 +386,7 @@ export const HOMEPAGE_ADDRESS_KEYS = Object.freeze(new Set(["url", "href"]));
394
386
  */
395
387
  function collectProse(text, field, kind, out, skipCode = false) {
396
388
  const pattern = new RegExp(MARKDOWN_LINK.source, "g");
397
- const matches =
398
- skipCode ?
399
- matchAllOutsideCode(text, pattern)
400
- : [...text.matchAll(pattern)];
389
+ const matches = skipCode ? matchAllOutsideCode(text, pattern) : [...text.matchAll(pattern)];
401
390
  for (const m of matches) out.push({ field, url: m[1], kind });
402
391
  }
403
392
 
package/engine/ids.mjs CHANGED
@@ -36,11 +36,7 @@ import crypto from "crypto";
36
36
  * @returns {string} A 16-character hexadecimal Foundry id.
37
37
  */
38
38
  export function makeId(namespace, value) {
39
- return crypto
40
- .createHash("sha1")
41
- .update(`${namespace}:${value}`)
42
- .digest("hex")
43
- .slice(0, 16);
39
+ return crypto.createHash("sha1").update(`${namespace}:${value}`).digest("hex").slice(0, 16);
44
40
  }
45
41
 
46
42
  /**
@@ -55,9 +51,7 @@ export function makeId(namespace, value) {
55
51
  *
56
52
  * @type {ReadonlySet<string>}
57
53
  */
58
- export const MAP_TYPES = Object.freeze(
59
- new Set(["battlemap", "localmap", "regionalmap"]),
60
- );
54
+ export const MAP_TYPES = Object.freeze(new Set(["battlemap", "localmap", "regionalmap"]));
61
55
 
62
56
  /**
63
57
  * Content type → the pack its documents compile into, and the document type
@@ -77,10 +71,7 @@ export const PACK_BY_TYPE = Object.freeze({
77
71
  macro: { pack: "macros", docType: "Macro" },
78
72
  being: { pack: "actors", docType: "Actor" },
79
73
  ...Object.fromEntries(
80
- [...MAP_TYPES].map((type) => [
81
- type,
82
- { pack: "scenes", docType: "Scene" },
83
- ]),
74
+ [...MAP_TYPES].map((type) => [type, { pack: "scenes", docType: "Scene" }]),
84
75
  ),
85
76
  });
86
77
 
@@ -72,9 +72,7 @@ export function itemTypes() {
72
72
  * @throws {Error} When the configuration registers no builder for `type`.
73
73
  */
74
74
  export function itemBuilder(type) {
75
- const builder = /** @type {Record<string, Function>} */ (
76
- loadPackConfig().itemBuilders
77
- )[type];
75
+ const builder = /** @type {Record<string, Function>} */ (loadPackConfig().itemBuilders)[type];
78
76
  if (typeof builder !== "function") {
79
77
  throw new Error(
80
78
  `No builder registered for item type "${type}" — add one to the ` +
@@ -112,9 +110,7 @@ export function itemBuilder(type) {
112
110
  * @throws {Error} When the type's registry entry pairs no `img`.
113
111
  */
114
112
  export function itemArt(type) {
115
- const art = /** @type {Record<string, string|undefined>} */ (
116
- loadPackConfig().itemArt
117
- )[type];
113
+ const art = /** @type {Record<string, string|undefined>} */ (loadPackConfig().itemArt)[type];
118
114
  if (!art) {
119
115
  throw new Error(
120
116
  `No default art for item type "${type}" — the note carries no ` +
@@ -45,13 +45,7 @@
45
45
 
46
46
  import log from "loglevel";
47
47
 
48
- import {
49
- sohlField,
50
- makeId,
51
- resolveName,
52
- defaultStats,
53
- md,
54
- } from "./helpers.mjs";
48
+ import { sohlField, makeId, resolveName, defaultStats, md } from "./helpers.mjs";
55
49
  import { BasePackCompiler } from "./base-compiler.mjs";
56
50
  import { anchorPageId } from "./wikilinks.mjs";
57
51
  import { hasDocEntry, itemDocEntryId } from "./item-docs.mjs";
@@ -98,12 +92,10 @@ export function splitPages(body, leadName = "Introduction") {
98
92
  // An H1 starts a page, as does any heading carrying an `{#slug}`
99
93
  // anchor: a Foundry UUID can only address a page, so a linkable
100
94
  // section has to be one.
101
- const headingMatch =
102
- !inCodeBlock ? line.match(/^\s*(#{1,6})\s+(.+?)\s*#*\s*$/) : null;
95
+ const headingMatch = !inCodeBlock ? line.match(/^\s*(#{1,6})\s+(.+?)\s*#*\s*$/) : null;
103
96
  const rawHeading = headingMatch?.[2]?.trim();
104
97
  const anchorMatch = rawHeading?.match(/^(.*?)\s*\{#([^}]+)\}\s*$/);
105
- const startsPage =
106
- headingMatch && (headingMatch[1].length === 1 || anchorMatch);
98
+ const startsPage = headingMatch && (headingMatch[1].length === 1 || anchorMatch);
107
99
  if (startsPage) {
108
100
  closeCurrent();
109
101
  current = {
@@ -371,8 +363,6 @@ export class Journals extends BasePackCompiler {
371
363
 
372
364
  /** @inheritdoc */
373
365
  reportDetail(stats) {
374
- log.debug(
375
- `Skipped ${stats.skippedOther} non-doc file(s) (not type:doc)`,
376
- );
366
+ log.debug(`Skipped ${stats.skippedOther} non-doc file(s) (not type:doc)`);
377
367
  }
378
368
  }
@@ -180,9 +180,7 @@ export const PACKAGE_BASE = Object.freeze({
180
180
  */
181
181
  function checkBase(base, what) {
182
182
  if (typeof base !== "string" || !base.endsWith("/")) {
183
- throw new Error(
184
- `${what}: package base ${JSON.stringify(base)} must end in a slash`,
185
- );
183
+ throw new Error(`${what}: package base ${JSON.stringify(base)} must end in a slash`);
186
184
  }
187
185
  return base;
188
186
  }
@@ -226,8 +224,7 @@ export function resolvePackageUrl(rel, base) {
226
224
  checkBase(base, "resolvePackageUrl");
227
225
  if (typeof rel !== "string" || !rel || rel.startsWith("/")) {
228
226
  throw new Error(
229
- `resolvePackageUrl: ${JSON.stringify(rel)} is not a package-` +
230
- `relative address`,
227
+ `resolvePackageUrl: ${JSON.stringify(rel)} is not a package-` + `relative address`,
231
228
  );
232
229
  }
233
230
  return `${base}${rel}`;
@@ -289,8 +286,7 @@ export function buildManifest(pkg, entries, base, foundryPackage) {
289
286
  // address, so there is no fact being restated, and an anchor is not
290
287
  // required to live inside its own entry. Publishing the complete link
291
288
  // also keeps the page-id hash out of the published contract entirely.
292
- if (e.anchors && Object.keys(e.anchors).length)
293
- entry.anchors = e.anchors;
289
+ if (e.anchors && Object.keys(e.anchors).length) entry.anchors = e.anchors;
294
290
  out[e.key ?? canonicalKey(pkg, type, shortcode)] = entry;
295
291
  }
296
292
  return {
@@ -327,12 +323,7 @@ export function writeManifests(entriesByPackage, dir, bases, foundryPackages) {
327
323
  fs.mkdirSync(dir, { recursive: true });
328
324
  const written = [];
329
325
  for (const [pkg, entries] of entriesByPackage) {
330
- const doc = buildManifest(
331
- pkg,
332
- entries,
333
- bases?.[pkg],
334
- foundryPackages?.[pkg],
335
- );
326
+ const doc = buildManifest(pkg, entries, bases?.[pkg], foundryPackages?.[pkg]);
336
327
  const file = path.join(dir, `${pkg}.json`);
337
328
  fs.writeFileSync(file, `${JSON.stringify(doc, null, 2)}\n`);
338
329
  written.push({
@@ -430,10 +421,7 @@ export function loadForeignManifests(dir, localPackages, bases = PACKAGE_BASE) {
430
421
  // Absent for an entry with no page. A consumer must
431
422
  // tolerate that rather than invent an href, exactly as
432
423
  // it already tolerates an entry with no `uuid`.
433
- url:
434
- v.path == null ?
435
- undefined
436
- : resolvePackageUrl(v.path, base),
424
+ url: v.path == null ? undefined : resolvePackageUrl(v.path, base),
437
425
  uuid: v.uuid,
438
426
  doc: v.doc,
439
427
  anchors: v.anchors,
package/engine/macros.mjs CHANGED
@@ -51,12 +51,7 @@
51
51
 
52
52
  import log from "loglevel";
53
53
 
54
- import {
55
- sohlField,
56
- resolveName,
57
- resolveImg,
58
- defaultStats,
59
- } from "./helpers.mjs";
54
+ import { sohlField, resolveName, resolveImg, defaultStats } from "./helpers.mjs";
60
55
  import { BasePackCompiler } from "./base-compiler.mjs";
61
56
  import { splitPages } from "./journals.mjs";
62
57
 
@@ -256,10 +251,7 @@ export function resolveMacroScope(fm, label) {
256
251
  * @returns {MacroDocument} The Macro document.
257
252
  * @throws {Error} When the frontmatter's macro type or scope is unusable.
258
253
  */
259
- export function buildMacroEntry(
260
- fm,
261
- { command, folder = null, stats = defaultStats() },
262
- ) {
254
+ export function buildMacroEntry(fm, { command, folder = null, stats = defaultStats() }) {
263
255
  const name = resolveName(fm);
264
256
  const id = fm.id;
265
257
  return {
@@ -142,11 +142,7 @@ export function entriesForNote(fm, name, address, body, ctx) {
142
142
  : undefined;
143
143
 
144
144
  if (hasDocEntry(fm.type)) {
145
- const docKey = canonicalKey(
146
- contentPackage,
147
- `doc${fm.type}`,
148
- fm.shortcode,
149
- );
145
+ const docKey = canonicalKey(contentPackage, `doc${fm.type}`, fm.shortcode);
150
146
  const docEntryId = fm.id ? itemDocEntryId(fm.id) : undefined;
151
147
  const docUuid = uuidFor("doc", docEntryId);
152
148
  return [
@@ -166,10 +162,7 @@ export function entriesForNote(fm, name, address, body, ctx) {
166
162
  // documentation, so both addresses resolve to the same URL.
167
163
  url,
168
164
  uuid: docUuid,
169
- anchors:
170
- docUuid ?
171
- anchorsOf(docUuid, docEntryId, body ?? "", name)
172
- : undefined,
165
+ anchors: docUuid ? anchorsOf(docUuid, docEntryId, body ?? "", name) : undefined,
173
166
  },
174
167
  ];
175
168
  }
@@ -184,10 +177,7 @@ export function entriesForNote(fm, name, address, body, ctx) {
184
177
  name,
185
178
  url,
186
179
  uuid: own,
187
- anchors:
188
- own && fm.type === "doc" ?
189
- anchorsOf(own, fm.id, body ?? "", name)
190
- : undefined,
180
+ anchors: own && fm.type === "doc" ? anchorsOf(own, fm.id, body ?? "", name) : undefined,
191
181
  },
192
182
  ];
193
183
  }
@@ -221,10 +211,9 @@ export function collectManifestEntries(contentBase, ctx) {
221
211
  // note yields two entries, so reporting one as the other overstates how
222
212
  // much of the tree is published.
223
213
  let notes = 0;
224
- for (const { frontmatter: fm, body, absPath } of walkMarkdownTree(
225
- contentBase,
226
- { skipDirectories: ctx.skipDirectories },
227
- )) {
214
+ for (const { frontmatter: fm, body, absPath } of walkMarkdownTree(contentBase, {
215
+ skipDirectories: ctx.skipDirectories,
216
+ })) {
228
217
  if (!fm) continue;
229
218
  const rel = path.relative(contentBase, absPath);
230
219
  assertNoDeclaredPackage(fm, {