@heroiclands/package-build 23.1.1 → 23.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (247) hide show
  1. package/CHANGELOG.md +69 -0
  2. package/bin/content-commands.mjs +68 -149
  3. package/bin/package-build.mjs +56 -10
  4. package/ci/check-banners.mjs +42 -6
  5. package/ci/confirm-npm-version.mjs +135 -0
  6. package/ci/content-format-reference.mjs +14 -5
  7. package/config.mjs +1 -0
  8. package/container.mjs +185 -4
  9. package/content-config.mjs +333 -210
  10. package/deploy.mjs +116 -10
  11. package/docs/api.md +238 -246
  12. package/docs/authoring/assets.md +11 -5
  13. package/docs/authoring/frontmatter.md +1 -1
  14. package/docs/authoring/links-and-markup.md +87 -0
  15. package/docs/commands.md +138 -99
  16. package/docs/configuration.md +277 -125
  17. package/docs/content-format.md +2 -0
  18. package/docs/diagnostics.md +48 -13
  19. package/docs/guides/book.md +341 -21
  20. package/docs/guides/e2e.md +13 -2
  21. package/docs/guides/icons.md +14 -4
  22. package/docs/guides/module-project.md +18 -8
  23. package/docs/guides/release-and-deploy.md +32 -0
  24. package/docs/guides/site.md +5 -2
  25. package/docs/project-setup.md +30 -10
  26. package/docs/reference/format-details.md +373 -170
  27. package/docs/reference/note-types.md +128 -109
  28. package/docs/reference/theme-pages.md +31 -6
  29. package/e2e.mjs +140 -28
  30. package/engine/actor-compiler.mjs +22 -31
  31. package/engine/address-charset.mjs +4 -17
  32. package/engine/address-fields.mjs +1 -1
  33. package/engine/address-render.mjs +12 -1
  34. package/engine/address-values.mjs +6 -0
  35. package/engine/address.mjs +46 -33
  36. package/engine/art-fields.mjs +30 -5
  37. package/engine/art-slots.mjs +10 -1
  38. package/engine/asset-bindings.mjs +12 -1
  39. package/engine/base-compiler.mjs +34 -65
  40. package/engine/being-age.mjs +2 -7
  41. package/engine/being-measurements.mjs +12 -1
  42. package/engine/calendar-artifacts.mjs +6 -0
  43. package/engine/calendar-choice.mjs +12 -1
  44. package/engine/calendar-format.mjs +12 -1
  45. package/engine/calendar-human.mjs +12 -1
  46. package/engine/compile-corpus.mjs +3 -1
  47. package/engine/content-address.mjs +9 -12
  48. package/engine/content-alerts.mjs +13 -1
  49. package/engine/content-blocks.mjs +14 -3
  50. package/engine/content-embeds.mjs +11 -3
  51. package/engine/content-figures.mjs +9 -0
  52. package/engine/content-footnotes.mjs +12 -1
  53. package/engine/content-format-check.mjs +11 -262
  54. package/engine/content-format.yaml +5 -2
  55. package/engine/content-images.mjs +3 -0
  56. package/engine/content-index.mjs +443 -20
  57. package/engine/content-links.mjs +29 -35
  58. package/engine/content-lint.mjs +2 -3
  59. package/engine/content-poetry.mjs +12 -1
  60. package/engine/content-slug.mjs +2 -14
  61. package/engine/content-spans.mjs +13 -1
  62. package/engine/content-tables.mjs +12 -1
  63. package/engine/culture-choice.mjs +210 -13
  64. package/engine/data-keys.mjs +19 -16
  65. package/engine/date-conversion.mjs +12 -1
  66. package/engine/declaration-check.mjs +9 -0
  67. package/engine/derived-fields.mjs +6 -7
  68. package/engine/diagnostics.mjs +34 -4
  69. package/engine/docs-checks.mjs +9 -0
  70. package/engine/document-subtypes.mjs +47 -34
  71. package/engine/event-views.mjs +139 -14
  72. package/engine/exported-scene.mjs +92 -28
  73. package/engine/extension-attributes.mjs +12 -1
  74. package/engine/field-spec.mjs +11 -102
  75. package/engine/folder-notes.mjs +0 -64
  76. package/engine/foreign-catalog.mjs +2 -1
  77. package/engine/format-generated.mjs +9 -0
  78. package/engine/foundry-entries.mjs +10 -28
  79. package/engine/frontmatter-lint.mjs +83 -392
  80. package/engine/frontmatter.mjs +20 -70
  81. package/engine/generate.mjs +10 -15
  82. package/engine/heading-attributes.mjs +12 -1
  83. package/engine/helpers.mjs +41 -102
  84. package/engine/holdings.mjs +1 -1
  85. package/engine/homepage.mjs +3 -10
  86. package/engine/ids.mjs +1 -167
  87. package/engine/index-records.mjs +6 -4
  88. package/engine/index.mjs +0 -3
  89. package/engine/infobox-render.mjs +15 -3
  90. package/engine/infobox.mjs +13 -14
  91. package/engine/item-compiler.mjs +4 -10
  92. package/engine/item-docs.mjs +3 -5
  93. package/engine/item-registry.mjs +2 -10
  94. package/engine/journals.mjs +1 -5
  95. package/engine/literature-notes.mjs +4 -12
  96. package/engine/macros.mjs +1 -2
  97. package/engine/map-graphviz.mjs +12 -1
  98. package/engine/markdown-expressions.mjs +12 -1
  99. package/engine/markdownlint-run.mjs +567 -0
  100. package/engine/metadata-index.mjs +42 -12
  101. package/engine/note-addresses.mjs +143 -35
  102. package/engine/note-claims.mjs +14 -28
  103. package/engine/note-dates.mjs +3 -3
  104. package/engine/note-frontmatter.mjs +6 -0
  105. package/engine/note-ids.mjs +8 -14
  106. package/engine/note-package.mjs +8 -25
  107. package/engine/note-state.mjs +1 -3
  108. package/engine/note-vocabulary.mjs +148 -84
  109. package/engine/number-words.mjs +12 -1
  110. package/engine/pack-config.mjs +15 -25
  111. package/engine/pack-router.mjs +10 -16
  112. package/engine/pathnames.mjs +8 -22
  113. package/engine/pdf-build.mjs +773 -121
  114. package/engine/pdf-coverage.mjs +188 -0
  115. package/engine/pdf-index.mjs +54 -7
  116. package/engine/pdf-pages.mjs +247 -0
  117. package/engine/pdf-render.mjs +114 -4
  118. package/engine/pdf-toc.mjs +29 -32
  119. package/engine/project-init.mjs +46 -6
  120. package/engine/prose-config.mjs +1 -1
  121. package/engine/prose-lint.mjs +52 -88
  122. package/engine/readability-lint.mjs +9 -0
  123. package/engine/reckoning-markers.mjs +12 -1
  124. package/engine/reference-targets.mjs +7 -0
  125. package/engine/runtime-only-fields.mjs +5 -8
  126. package/engine/scene-levels.mjs +2 -2
  127. package/engine/scenes.mjs +1 -1
  128. package/engine/shortcode-references.mjs +7 -0
  129. package/engine/site-build.mjs +30 -16
  130. package/engine/site-index.mjs +10 -16
  131. package/engine/site-preview.mjs +6 -0
  132. package/engine/site-root.mjs +8 -1
  133. package/engine/social-tie-terms.mjs +12 -1
  134. package/engine/social-ties.mjs +3 -0
  135. package/engine/sql-tables.mjs +56 -20
  136. package/engine/standing-terms.mjs +11 -1
  137. package/engine/standings.mjs +11 -27
  138. package/engine/system-block.mjs +39 -141
  139. package/engine/system-vocabulary.mjs +6 -0
  140. package/engine/walk-files.mjs +69 -0
  141. package/engine/web-wikilinks.mjs +23 -3
  142. package/engine/wikilink-syntax.mjs +32 -21
  143. package/engine/wikilinks.mjs +27 -16
  144. package/githooks/attribution.mjs +8 -0
  145. package/githooks/commit-message.mjs +9 -0
  146. package/hm3/actors.mjs +9 -48
  147. package/hm3/default-item-art.mjs +9 -9
  148. package/hm3/item-fields.mjs +2 -9
  149. package/hm3/template-priority.mjs +6 -7
  150. package/hugo-theme/data/banner-kinds.yaml +78 -0
  151. package/hugo-theme/data/banners.yaml +2 -3
  152. package/hugo-theme/layouts/404.html +3 -3
  153. package/hugo-theme/layouts/partials/banner-url.html +31 -7
  154. package/hugo-theme/layouts/partials/hero-banner.html +13 -14
  155. package/hugo-theme/layouts/partials/related.html +1 -1
  156. package/hugo-theme/layouts/partials/warn-missing-banner.html +1 -1
  157. package/hugo-theme/static/css/style.css +1 -1
  158. package/labels.mjs +2 -2
  159. package/manifest.mjs +11 -4
  160. package/markdownlint-config.mjs +1 -1
  161. package/package.json +6 -3
  162. package/release.mjs +21 -14
  163. package/sohl/actors.mjs +16 -27
  164. package/sohl/default-item-art.mjs +3 -3
  165. package/sohl/document-subtypes.mjs +1 -16
  166. package/sohl/infobox.mjs +2 -3
  167. package/sohl/item-builders.mjs +5 -8
  168. package/sohl/item-fields.mjs +5 -35
  169. package/sohl/items.mjs +0 -4
  170. package/sohl/kb-passes.mjs +3 -3
  171. package/types/container.d.mts +116 -5
  172. package/types/content-config.d.mts +83 -35
  173. package/types/deploy.d.mts +42 -6
  174. package/types/e2e.d.mts +35 -3
  175. package/types/engine/address-charset.d.mts +4 -17
  176. package/types/engine/address.d.mts +17 -8
  177. package/types/engine/art-fields.d.mts +7 -4
  178. package/types/engine/art-slots.d.mts +6 -0
  179. package/types/engine/base-compiler.d.mts +15 -17
  180. package/types/engine/content-address.d.mts +9 -12
  181. package/types/engine/content-embeds.d.mts +4 -2
  182. package/types/engine/content-format-check.d.mts +0 -64
  183. package/types/engine/content-index.d.mts +82 -3
  184. package/types/engine/content-links.d.mts +2 -4
  185. package/types/engine/culture-choice.d.mts +51 -8
  186. package/types/engine/data-keys.d.mts +2 -2
  187. package/types/engine/derived-fields.d.mts +1 -2
  188. package/types/engine/diagnostics.d.mts +27 -4
  189. package/types/engine/document-subtypes.d.mts +12 -31
  190. package/types/engine/event-views.d.mts +14 -2
  191. package/types/engine/exported-scene.d.mts +3 -2
  192. package/types/engine/field-spec.d.mts +13 -122
  193. package/types/engine/folder-notes.d.mts +0 -39
  194. package/types/engine/foreign-catalog.d.mts +2 -1
  195. package/types/engine/foundry-entries.d.mts +4 -5
  196. package/types/engine/frontmatter-lint.d.mts +2 -2
  197. package/types/engine/frontmatter.d.mts +19 -45
  198. package/types/engine/generate.d.mts +1 -1
  199. package/types/engine/helpers.d.mts +25 -42
  200. package/types/engine/homepage.d.mts +3 -10
  201. package/types/engine/ids.d.mts +0 -114
  202. package/types/engine/index-records.d.mts +6 -4
  203. package/types/engine/index.d.mts +0 -1
  204. package/types/engine/infobox-render.d.mts +7 -1
  205. package/types/engine/infobox.d.mts +3 -2
  206. package/types/engine/item-docs.d.mts +1 -1
  207. package/types/engine/item-registry.d.mts +2 -4
  208. package/types/engine/literature-notes.d.mts +1 -1
  209. package/types/engine/markdownlint-run.d.mts +40 -0
  210. package/types/engine/metadata-index.d.mts +9 -1
  211. package/types/engine/note-addresses.d.mts +27 -2
  212. package/types/engine/note-claims.d.mts +3 -5
  213. package/types/engine/note-ids.d.mts +2 -4
  214. package/types/engine/note-package.d.mts +1 -1
  215. package/types/engine/note-state.d.mts +1 -3
  216. package/types/engine/note-vocabulary.d.mts +28 -21
  217. package/types/engine/pack-config.d.mts +2 -6
  218. package/types/engine/pack-router.d.mts +4 -4
  219. package/types/engine/pathnames.d.mts +3 -3
  220. package/types/engine/pdf-build.d.mts +98 -12
  221. package/types/engine/pdf-coverage.d.mts +60 -0
  222. package/types/engine/pdf-index.d.mts +34 -5
  223. package/types/engine/pdf-pages.d.mts +143 -0
  224. package/types/engine/pdf-render.d.mts +45 -1
  225. package/types/engine/pdf-toc.d.mts +12 -14
  226. package/types/engine/prose-config.d.mts +1 -1
  227. package/types/engine/prose-lint.d.mts +11 -10
  228. package/types/engine/runtime-only-fields.d.mts +2 -2
  229. package/types/engine/site-build.d.mts +9 -5
  230. package/types/engine/site-index.d.mts +4 -5
  231. package/types/engine/site-root.d.mts +1 -1
  232. package/types/engine/sql-tables.d.mts +31 -2
  233. package/types/engine/standing-terms.d.mts +2 -1
  234. package/types/engine/standings.d.mts +7 -9
  235. package/types/engine/system-block.d.mts +10 -44
  236. package/types/engine/walk-files.d.mts +15 -0
  237. package/types/engine/wikilink-syntax.d.mts +18 -19
  238. package/types/hm3/actors.d.mts +1 -2
  239. package/types/hm3/item-fields.d.mts +2 -4
  240. package/types/hm3/template-priority.d.mts +6 -7
  241. package/types/manifest.d.mts +3 -2
  242. package/types/release.d.mts +8 -7
  243. package/types/sohl/actors.d.mts +2 -1
  244. package/types/sohl/document-subtypes.d.mts +1 -2
  245. package/types/sohl/item-fields.d.mts +3 -7
  246. package/engine/retired-fields.mjs +0 -631
  247. package/types/engine/retired-fields.d.mts +0 -354
@@ -43,9 +43,9 @@
43
43
  * @module
44
44
  */
45
45
 
46
- import { legacyKeyOf, resolveFieldValue, retiredTopLevelKey, setPath } from "./system-block.mjs";
46
+ import { resolveFieldValue, setPath } from "./system-block.mjs";
47
47
 
48
- export { legacyKeyOf, retiredTopLevelKey, setPath };
48
+ export { setPath };
49
49
 
50
50
  /**
51
51
  * @typedef {object} FieldSpec
@@ -61,29 +61,10 @@ export { legacyKeyOf, retiredTopLevelKey, setPath };
61
61
  * degenerate case where the shared source and the system destination happen
62
62
  * to share a name. They constantly do not — one shared `data.portrait` feeds
63
63
  * `sohl.system.portrait` *and* `hm3.system.bioImage` — so the source is
64
- * declared rather than matched by spelling. The in-block position is
65
- * still read, second, until the corpus moves off it — keyed on
66
- * `legacyKey` where the two spellings differ.
64
+ * declared rather than matched by spelling. A name that is not a path into
65
+ * `data:` is also read inside the system block, second.
67
66
  *
68
67
  * Absent means the value is not authored at all — see `value`.
69
- * @property {string} [legacyKey] - **The key this field is authored at inside
70
- * the system block** — the second position of the resolution order — when
71
- * that is not `name`. Absent, the position is keyed on `name`.
72
- *
73
- * As one property the two would hold only while a field's
74
- * shared source and its in-block key were the same word. `data:` ended
75
- * that: a shared source is a path into a container, so `data.species` and
76
- * `species` name two different places and no single value reached both.
77
- * `name: "species"` could not see `data.species`; `name: "data.species"`
78
- * could not see `hm3.species`; and each yielded the field's **default**
79
- * wherever only the other position was authored, with the note compiling and
80
- * the value simply gone.
81
- *
82
- * Declaring both restores the shape every other retirement in this package
83
- * uses — read both spellings, let the current one win, and *report* the
84
- * retiring one — so a field can move into `data:` while the corpus catches
85
- * up, instead of on a flag day across four repositories. A declaration that
86
- * names one is mid-sweep by construction; see {@link readsLegacyKey}.
87
68
  * @property {string} [topLevelMeans] - **Why the note's top-level key of this
88
69
  * name is not this field's source** — declared wherever that key's spelling
89
70
  * means something else at the note level, or the closed top-level
@@ -109,7 +90,7 @@ export { legacyKeyOf, retiredTopLevelKey, setPath };
109
90
  *
110
91
  * The exempted field is still authorable, at both of the positions that
111
92
  * describe the *document* rather than the note: `<system>.system.<to>` and
112
- * the legacy in-block `<system>.<name>`. Absent means the ordinary case —
93
+ * the in-block `<system>.<name>`. Absent means the ordinary case —
113
94
  * the top level is read, as the third step.
114
95
  *
115
96
  * **It is read from the other side too**, because the statement is symmetric:
@@ -211,7 +192,7 @@ export { legacyKeyOf, retiredTopLevelKey, setPath };
211
192
  * itself a valid world time, which is why such a field is nullable rather
212
193
  * than sentinelled and why a default cannot stand in for one.
213
194
  *
214
- * Nothing used to stop a note writing one. The three checks that might have
195
+ * Nothing else stops a note writing one. The three checks that might have
215
196
  * each declined for its own correct reason —
216
197
  * {@link module:engine/system-block.unknownBlockKeys} reads the block's top
217
198
  * level and never descends into `system:`;
@@ -306,57 +287,12 @@ export const BLANK_IS_DEFAULT = Object.freeze({
306
287
  /* Applying a declaration */
307
288
  /* --------------------------------------------------------------------- */
308
289
 
309
- /**
310
- * Whether a resolution read a field from the position it is being swept off.
311
- *
312
- * The sweep's progress signal, in one predicate so the compile-time report and
313
- * the frontmatter lint cannot disagree about what counts — the role
314
- * {@link module:engine/retired-fields.declaresRetiredAlias} plays for a renamed
315
- * field.
316
- *
317
- * **Only for a field that declares a `legacyKey`.** Every other field's
318
- * in-block position is simply where it lives; reporting those would put a
319
- * finding on every field of every note in every tree, which is the corpus
320
- * migration rather than a signal anyone could act on.
321
- *
322
- * @param {FieldSpec} field - The declaration.
323
- * @param {import("./system-block.mjs").FieldSource} from - Where
324
- * {@link resolveFieldValue} said the value came from.
325
- * @returns {boolean} True when the value came from the retiring position.
326
- */
327
- export function readsLegacyKey(field, from) {
328
- return field?.legacyKey !== undefined && from === "block";
329
- }
330
-
331
- /**
332
- * Whether a resolution read a field from the top-level key `data:` gathered it
333
- * off — the shared level's retiring position.
334
- *
335
- * {@link readsLegacyKey}'s sibling, and the same signal: a finding here counts
336
- * one note still on the pre-`data:` spelling, so the sweep has something to
337
- * count down instead of a corpus nobody has surveyed.
338
- *
339
- * The `from` tag already carries the whole answer — step 3b is the only thing
340
- * that produces it, and it produces it only for a `data.` source — so this is a
341
- * name for the question rather than a second test of it. Named all the same,
342
- * because a compile-time report and the frontmatter lint both ask it and must
343
- * not drift apart about what counts.
344
- *
345
- * @param {FieldSpec} field - The declaration.
346
- * @param {import("./system-block.mjs").FieldSource} from - Where
347
- * {@link resolveFieldValue} said the value came from.
348
- * @returns {boolean} True when the value came from the retiring top-level key.
349
- */
350
- export function readsRetiredTopLevel(field, from) {
351
- return from === "topLevel" && retiredTopLevelKey(field) !== undefined;
352
- }
353
-
354
290
  /**
355
291
  * Read one declared field out of a note's frontmatter.
356
292
  *
357
293
  * The *position* is resolved by {@link resolveFieldValue} — `<system>.system`
358
- * first, then the legacy in-block key, then the declared shared source, then
359
- * the default. The **coercion** is applied here, once, wherever the value
294
+ * first, then the in-block key, then the declared shared source, then the
295
+ * default. The **coercion** is applied here, once, wherever the value
360
296
  * came from: a field's `read` is a statement about the field, not about where
361
297
  * an author happened to write it, so `weight: "7"` reads as `7` at every one of
362
298
  * those positions.
@@ -367,17 +303,6 @@ export function readsRetiredTopLevel(field, from) {
367
303
  * @param {string} [options.block="sohl"] - Which system's block to resolve
368
304
  * against. The default is the one block every existing tree authors; a
369
305
  * second system passes its own.
370
- * @param {(field: FieldSpec) => void} [options.onLegacyKey] - Called with each
371
- * field read from the position it is being swept off. A callback
372
- * rather than a returned list because the caller is a compiler, which already
373
- * knows the note and how to locate a key in it; this module knows neither and
374
- * would have to invent a finding shape to say so.
375
- * @param {(field: FieldSpec) => void} [options.onRetiredTopLevel] - Called with
376
- * each field read from the top-level key `data:` gathered it off. The
377
- * shared level's counterpart to `onLegacyKey`, and a separate callback
378
- * because it is a separate position: a note may have moved one of the two and
379
- * not the other, and a caller that conflated them would tell its author to
380
- * fix the wrong line.
381
306
  * @returns {any} The value to emit.
382
307
  */
383
308
  export function readField(field, fm, options = {}) {
@@ -403,18 +328,12 @@ export function readField(field, fm, options = {}) {
403
328
  * @param {object} [options] - Options, as {@link readField} takes them.
404
329
  * @param {string} [options.block="sohl"] - Which system's block to resolve
405
330
  * against.
406
- * @param {(field: FieldSpec) => void} [options.onLegacyKey] - See
407
- * {@link readField}.
408
- * @param {(field: FieldSpec) => void} [options.onRetiredTopLevel] - See
409
- * {@link readField}.
410
331
  * @returns {{value: any, from: import("./system-block.mjs").FieldSource}} The
411
332
  * value to emit, and the position it was read from.
412
333
  */
413
- export function readFieldEntry(field, fm, { block = "sohl", onLegacyKey, onRetiredTopLevel } = {}) {
334
+ export function readFieldEntry(field, fm, { block = "sohl" } = {}) {
414
335
  const { value, from } = resolveFieldValue(field, fm, { block });
415
336
  if (from === "value") return { value, from };
416
- if (onLegacyKey && readsLegacyKey(field, from)) onLegacyKey(field);
417
- if (onRetiredTopLevel && readsRetiredTopLevel(field, from)) onRetiredTopLevel(field);
418
337
  return { value: field.read ? field.read(value, { fm, field }) : value, from };
419
338
  }
420
339
 
@@ -453,15 +372,9 @@ export function isAuthored(from, value) {
453
372
  * @param {string} [options.block="sohl"] - Which system's block the builder
454
373
  * reads. One declaration compiles against any block, which is what lets two
455
374
  * systems declare the same shared source and different destinations.
456
- * @param {(field: FieldSpec) => void} [options.onLegacyKey] - Passed through to
457
- * {@link readField}: called with each field the note authored at the position
458
- * it is being swept off.
459
- * @param {(field: FieldSpec) => void} [options.onRetiredTopLevel] - Passed
460
- * through to {@link readField}: called with each field the note authored at
461
- * the top-level key `data:` gathered it off.
462
375
  * @returns {(fm: object) => object} A `system`-block builder.
463
376
  */
464
- export function buildFromFields(fields, { block = "sohl", onLegacyKey, onRetiredTopLevel } = {}) {
377
+ export function buildFromFields(fields, { block = "sohl" } = {}) {
465
378
  return function buildDeclaredSystem(fm) {
466
379
  const out = {};
467
380
  for (const field of fields) {
@@ -474,11 +387,7 @@ export function buildFromFields(fields, { block = "sohl", onLegacyKey, onRetired
474
387
  // `initial` standing; writing the `undefined` a source-less
475
388
  // declaration resolves to would put the key in the document.
476
389
  if (field.runtimeOnly) continue;
477
- const { value, from } = readFieldEntry(field, fm, {
478
- block,
479
- onLegacyKey,
480
- onRetiredTopLevel,
481
- });
390
+ const { value, from } = readFieldEntry(field, fm, { block });
482
391
  // The other conditional row: a field whose *absence* is meaningful.
483
392
  // Writing a declared default would answer a question the
484
393
  // note did not ask — "this affliction's onset takes `null` days" —
@@ -57,7 +57,6 @@ import { NO_SYSTEM, canonicalKey, readCanonicalKey } from "./content-address.mjs
57
57
  import { parseAddress, renderAddress } from "./address.mjs";
58
58
  import { ADDRESS_SEGMENT_PATTERN, isAddressSegment } from "./address-charset.mjs";
59
59
  import { makeId } from "./ids.mjs";
60
- import { locateFrontmatterKey } from "./retired-fields.mjs";
61
60
 
62
61
  /**
63
62
  * The note type a folder is authored as.
@@ -522,66 +521,3 @@ export function folderDocument(folder, parent, documentType, stats) {
522
521
  _key: `!folders!${folder.id}`,
523
522
  };
524
523
  }
525
-
526
- /**
527
- * Refuse a note that declares the retired `folder:` spelling.
528
- *
529
- * `folder:` named a compendium folder by the raw Foundry id declared in a
530
- * per-pack `*-folders.yaml`. Both halves are retired together: the id
531
- * spelling has nothing left to resolve against once the YAML is gone, and the
532
- * YAML has no reader once the spelling is refused.
533
- *
534
- * **Presence is the whole test.** An empty `folder:` — which parses as `null`
535
- * — is still the field, and a value that happens to match a folder note's id
536
- * is still the retired spelling. There is no value that makes writing it
537
- * correct, so the message says what to write instead rather than which value
538
- * to change.
539
- *
540
- * **Both positions**, because notes wrote it both ways: top-level, and inside
541
- * the `sohl:` block. Checking only the more common one is how a sweep leaves
542
- * a tail behind.
543
- *
544
- * Refused rather than ignored, on the pattern `package:` set: a retired field
545
- * left ignored reads to its author as though it still works — the note says
546
- * one thing and the build does another, and nothing says so.
547
- *
548
- * @param {object|null|undefined} fm - Parsed frontmatter, or nothing when it
549
- * could not be parsed.
550
- * @param {object} [options] - Options.
551
- * @param {string} [options.file] - The note's path, named in the message. Omit
552
- * it where the caller emits through a diagnostic, which puts the locator at
553
- * the start of the line already — repeating it prints the path twice.
554
- * @param {string} [options.absPath] - The note's file on disk, read only on
555
- * the failing path to locate the offending line and column. The position
556
- * rides on the thrown error as `position`, for a caller that emits a
557
- * diagnostic.
558
- * @returns {void}
559
- * @throws {Error} When the note declares the field.
560
- */
561
- export function assertNoDeclaredFolder(fm, { file, absPath } = {}) {
562
- if (!fm || typeof fm !== "object") return;
563
- const sohl = fm.sohl;
564
- const inBlock = !!sohl && typeof sohl === "object" && Object.hasOwn(sohl, "folder");
565
- if (!Object.hasOwn(fm, "folder") && !inBlock) return;
566
-
567
- const declared = inBlock ? sohl.folder : fm.folder;
568
- const wrote =
569
- declared === null || declared === undefined || declared === "" ?
570
- "`folder:`"
571
- : `\`folder: ${declared}\``;
572
-
573
- const err = new Error(
574
- `${wrote} is a retired frontmatter field — write \`packFolder\` ` +
575
- `instead` +
576
- (file ? ` — ${file}` : "") +
577
- `. A folder is a note now, and \`packFolder\` names it by its ` +
578
- `address (\`packFolder: miscgear\`), not by the Foundry id a ` +
579
- `retired \`*-folders.yaml\` used to declare.`,
580
- );
581
- // Where the field is, so the caller's diagnostic opens on the line that
582
- // has to be rewritten. Read here rather than carried through every walk:
583
- // this is the failing path, and the build stops on it.
584
- const position = locateFrontmatterKey(absPath, "folder");
585
- if (position) err.position = position;
586
- throw err;
587
- }
@@ -795,7 +795,8 @@ function findLocalIndex(root, name) {
795
795
  * Fetch every declared dependency's content index.
796
796
  *
797
797
  * A wider set than {@link fetchAllCatalogs}: an index is fetched for *every*
798
- * dependency, a catalogue only for those declaring `itemCatalog: true`. See
798
+ * dependency, plus every other relationship declaring `itemCatalog: true`; a
799
+ * catalogue only for those declaring `itemCatalog: true`. See
799
800
  * {@link metadataRelationships} for why the two sets differ.
800
801
  *
801
802
  * @param {object} config - The resolved build configuration.
@@ -1,4 +1,13 @@
1
1
  /*
2
+ * This file is part of the Song of Heroic Lands (SoHL) system for Foundry VTT.
3
+ * Copyright (c) 2024-2026 Tom Rodriguez ("Toasty") — <toasty@heroiclands.org>
4
+ *
5
+ * This work is licensed under the GNU General Public License v3.0 (GPLv3).
6
+ * You may copy, modify, and distribute it under the terms of that license.
7
+ *
8
+ * For full terms, see the LICENSE.md file in the project root or visit:
9
+ * https://www.gnu.org/licenses/gpl-3.0.html
10
+ *
2
11
  * SPDX-License-Identifier: GPL-3.0-or-later
3
12
  */
4
13
 
@@ -36,8 +36,7 @@
36
36
  * no uniqueness check stands between the two. The system segment goes with the
37
37
  * package because a note publishes one page however many systems' documents it
38
38
  * compiles into. Every entry is
39
- * derivable that way, sections being retired — the section landing was the one
40
- * that was not. The field is still written rather than left for a consumer to
39
+ * derivable that way. The field is still written rather than left for a consumer to
41
40
  * compute, because an absent `path` already means something else entirely (a
42
41
  * package that publishes no pages).
43
42
  *
@@ -72,19 +71,12 @@ import { DEFAULT_DOCUMENT_SUBTYPES, SYSTEM_DOCUMENT_CLASSES } from "./subtype-re
72
71
  import { carriesSystemBlock } from "./system-block.mjs";
73
72
  import { walkMarkdownTree } from "./helpers.mjs";
74
73
  import { resolveNoteId } from "./note-ids.mjs";
75
- import { compendiumUuid, currentType, packForType, pageUuid } from "./ids.mjs";
74
+ import { compendiumUuid, packForType, pageUuid } from "./ids.mjs";
76
75
  import { hasDocEntry, itemDocEntryId } from "./item-docs.mjs";
77
76
  import { journalHasContent } from "./note-state.mjs";
78
77
  import { isHomepage } from "./homepage.mjs";
79
78
  import { declaresNoPack } from "./pack-router.mjs";
80
79
  import { assertNoDeclaredPackage } from "./note-package.mjs";
81
- import { assertNoDeclaredFolder } from "./folder-notes.mjs";
82
- import {
83
- assertNoAliasesField,
84
- assertNoDraftField,
85
- assertNoSectionField,
86
- assertNoTraitsField,
87
- } from "./retired-fields.mjs";
88
80
  import { collectAnchors } from "./anchors.mjs";
89
81
  import { journalPageId, splitPages } from "./journals.mjs";
90
82
  import { routerFor } from "./pack-router.mjs";
@@ -180,11 +172,9 @@ export function entriesForNote(fm, name, address, body, ctx) {
180
172
  }
181
173
 
182
174
  // A type this cannot name a single compendium document for has no UUID
183
- // to publish, whatever id it derives. That used to follow from such a
184
- // note authoring no `id:`; every addressable note derives
185
- // one, so "has an id" stopped being evidence a document exists and the
186
- // rule is stated where it belongs — beside the addresses — rather than
187
- // resting on an absent field. `collectFoundryEntries` skips such a note
175
+ // to publish, whatever id it derives. Every addressable note derives an
176
+ // id, so "has an id" is no evidence a document exists; the rule is
177
+ // stated beside the addresses. `collectFoundryEntries` skips such a note
188
178
  // outright; the content index calls this function directly, so the
189
179
  // guard has to live on this side of it.
190
180
  //
@@ -250,9 +240,7 @@ export function entriesForNote(fm, name, address, body, ctx) {
250
240
  };
251
241
 
252
242
  const carriesDoc =
253
- ctx.docEntryTypes ?
254
- ctx.docEntryTypes.has(String(currentType(fm.type)))
255
- : hasDocEntry(fm.type);
243
+ ctx.docEntryTypes ? ctx.docEntryTypes.has(String(fm.type)) : hasDocEntry(fm.type);
256
244
  if (carriesDoc) {
257
245
  // `NO_SYSTEM`, whatever the item is: a documentation journal is a
258
246
  // JournalEntry, which no game system defines, and there is one of them
@@ -311,11 +299,10 @@ export function entriesForNote(fm, name, address, body, ctx) {
311
299
  * Every note this package publishes, as manifest entries.
312
300
  *
313
301
  * Every note in the tree is this package's, so nothing here selects by package:
314
- * the key's first segment is `contentPackage`. A note still declaring the
315
- * retired `package:` or `draft:` field **throws** rather than being skipped —
316
- * skipping one silently is how a whole tree came to be filtered out of a
317
- * manifest that then claimed the package published nothing, and it is what let
318
- * a drafted note's inbound links look like links to a note that never existed.
302
+ * the key's first segment is `contentPackage`. A note declaring `package:`
303
+ * **throws** rather than being skipped — skipping one silently is how a whole
304
+ * tree came to be filtered out of a manifest that then claimed the package
305
+ * published nothing.
319
306
  *
320
307
  * A note that has no address is **reported, not guessed** — the finding carries
321
308
  * the file and the reason, so a caller can print it or fail on it. Inventing an
@@ -349,11 +336,6 @@ export function collectFoundryEntries(contentBase, ctx) {
349
336
  absPath,
350
337
  configured: ctx.contentPackage,
351
338
  });
352
- assertNoDeclaredFolder(fm, { file: rel, absPath });
353
- assertNoDraftField(fm, { file: rel, absPath });
354
- assertNoAliasesField(fm, { file: rel, absPath });
355
- assertNoSectionField(fm, { file: rel, absPath });
356
- assertNoTraitsField(fm, { file: rel, absPath });
357
339
  if (!fm.type || !fm.shortcode) continue;
358
340
  // A homepage is addressed like every other note, and a
359
341
  // shortcode alone would now put it here. It stays out for the reason it