@heroiclands/package-build 20.3.0 → 20.4.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 (178) hide show
  1. package/CHANGELOG.md +97 -0
  2. package/CONTENT.md +111 -92
  3. package/README.md +2 -9
  4. package/bin/content-build.mjs +70 -61
  5. package/bin/package-build.mjs +2 -2
  6. package/config.mjs +6 -8
  7. package/content-config.mjs +187 -64
  8. package/docs/content-format.md +57 -68
  9. package/e2e.mjs +4 -4
  10. package/engine/actor-compiler.mjs +36 -36
  11. package/engine/address-charset.mjs +6 -6
  12. package/engine/address-diff.mjs +12 -11
  13. package/engine/anchored-sections.mjs +1 -1
  14. package/engine/anchors.mjs +1 -1
  15. package/engine/base-compiler.mjs +36 -38
  16. package/engine/bundle-notes.mjs +4 -4
  17. package/engine/bundles.mjs +8 -8
  18. package/engine/code-fences.mjs +3 -3
  19. package/engine/compendiums.mjs +8 -8
  20. package/engine/compile-corpus.mjs +4 -5
  21. package/engine/content-address.mjs +15 -15
  22. package/engine/content-charset.mjs +1 -1
  23. package/engine/content-format-check.mjs +24 -25
  24. package/engine/content-format.mjs +8 -8
  25. package/engine/content-html.mjs +202 -0
  26. package/engine/content-icons.mjs +225 -98
  27. package/engine/content-index.mjs +17 -17
  28. package/engine/content-links.mjs +30 -30
  29. package/engine/content-lint.mjs +20 -24
  30. package/engine/content-package.mjs +7 -9
  31. package/engine/content-slug.mjs +2 -2
  32. package/engine/content-tables.mjs +7 -8
  33. package/engine/content-tree.mjs +1 -1
  34. package/engine/derived-fields.mjs +174 -0
  35. package/engine/diagnostics.mjs +3 -4
  36. package/engine/document-subtypes.mjs +6 -7
  37. package/engine/field-reference.mjs +8 -8
  38. package/engine/field-spec.mjs +29 -30
  39. package/engine/folder-notes.mjs +14 -14
  40. package/engine/foreign-catalog.mjs +8 -9
  41. package/engine/foundry-entries.mjs +19 -20
  42. package/engine/frontmatter-lint.mjs +64 -69
  43. package/engine/frontmatter.mjs +11 -11
  44. package/engine/generate.mjs +39 -39
  45. package/engine/helpers.mjs +63 -54
  46. package/engine/homepage.mjs +20 -22
  47. package/engine/ids.mjs +15 -15
  48. package/engine/index-records.mjs +4 -4
  49. package/engine/index.mjs +14 -8
  50. package/engine/item-compiler.mjs +54 -29
  51. package/engine/item-docs.mjs +11 -13
  52. package/engine/item-registry.mjs +13 -13
  53. package/engine/journals.mjs +15 -15
  54. package/engine/macros.mjs +3 -3
  55. package/engine/map-notes.mjs +6 -6
  56. package/engine/metadata-index.mjs +5 -5
  57. package/engine/note-claims.mjs +36 -34
  58. package/engine/note-ids.mjs +5 -5
  59. package/engine/note-package.mjs +4 -4
  60. package/engine/note-renames.mjs +3 -3
  61. package/engine/note-schemas.mjs +3 -3
  62. package/engine/note-vocabulary.mjs +27 -26
  63. package/engine/pack-config.mjs +13 -13
  64. package/engine/pack-router.mjs +0 -0
  65. package/engine/prose-config.mjs +9 -9
  66. package/engine/prose-lint.mjs +12 -13
  67. package/engine/region-events.mjs +2 -2
  68. package/engine/retired-fields.mjs +24 -22
  69. package/engine/runtime-only-fields.mjs +1 -1
  70. package/engine/scene-levels.mjs +1 -1
  71. package/engine/scenes.mjs +19 -20
  72. package/engine/schema-check.mjs +20 -20
  73. package/engine/schema-extract.mjs +1 -1
  74. package/engine/site-build.mjs +45 -47
  75. package/engine/site-index.mjs +17 -18
  76. package/engine/sql-tables.mjs +21 -13
  77. package/engine/subtype-registry.mjs +5 -4
  78. package/engine/system-block.mjs +18 -19
  79. package/engine/systems.mjs +2 -2
  80. package/engine/web-wikilinks.mjs +35 -35
  81. package/engine/wikilink-syntax.mjs +16 -16
  82. package/engine/wikilinks.mjs +39 -39
  83. package/hm3/actors.mjs +22 -22
  84. package/hm3/document-subtypes.mjs +5 -5
  85. package/hm3/index.mjs +2 -2
  86. package/hm3/item-builders.mjs +1 -1
  87. package/hm3/item-fields.mjs +3 -3
  88. package/hm3/items.mjs +20 -8
  89. package/hm3/template-priority.mjs +2 -2
  90. package/lang.mjs +3 -3
  91. package/manifest.mjs +17 -20
  92. package/package.json +1 -2
  93. package/release.mjs +3 -3
  94. package/sohl/actors.mjs +28 -28
  95. package/sohl/affiliation-standings.mjs +2 -2
  96. package/sohl/being-info.mjs +5 -5
  97. package/sohl/default-item-art.mjs +5 -5
  98. package/sohl/document-subtypes.mjs +5 -5
  99. package/sohl/index.mjs +3 -3
  100. package/sohl/item-builders.mjs +7 -7
  101. package/sohl/item-fields.mjs +8 -9
  102. package/sohl/items.mjs +20 -6
  103. package/sohl/kb-passes.mjs +5 -5
  104. package/sohl/note-schemas.mjs +7 -7
  105. package/sohl/skill-base.mjs +1 -1
  106. package/types/content-config.d.mts +25 -24
  107. package/types/e2e.d.mts +3 -3
  108. package/types/engine/actor-compiler.d.mts +14 -13
  109. package/types/engine/address-charset.d.mts +6 -6
  110. package/types/engine/address-diff.d.mts +3 -3
  111. package/types/engine/base-compiler.d.mts +17 -19
  112. package/types/engine/bundle-notes.d.mts +3 -3
  113. package/types/engine/bundles.d.mts +1 -1
  114. package/types/engine/code-fences.d.mts +3 -3
  115. package/types/engine/compendiums.d.mts +3 -3
  116. package/types/engine/compile-corpus.d.mts +1 -1
  117. package/types/engine/content-address.d.mts +11 -11
  118. package/types/engine/content-format-check.d.mts +6 -6
  119. package/types/engine/content-format.d.mts +2 -2
  120. package/types/engine/content-html.d.mts +78 -0
  121. package/types/engine/content-icons.d.mts +150 -62
  122. package/types/engine/content-index.d.mts +2 -2
  123. package/types/engine/content-links.d.mts +8 -8
  124. package/types/engine/content-lint.d.mts +2 -2
  125. package/types/engine/content-package.d.mts +6 -8
  126. package/types/engine/derived-fields.d.mts +101 -0
  127. package/types/engine/diagnostics.d.mts +2 -2
  128. package/types/engine/document-subtypes.d.mts +3 -3
  129. package/types/engine/field-spec.d.mts +37 -39
  130. package/types/engine/folder-notes.d.mts +4 -5
  131. package/types/engine/foreign-catalog.d.mts +3 -3
  132. package/types/engine/foundry-entries.d.mts +6 -7
  133. package/types/engine/frontmatter-lint.d.mts +7 -7
  134. package/types/engine/frontmatter.d.mts +7 -7
  135. package/types/engine/generate.d.mts +7 -7
  136. package/types/engine/helpers.d.mts +25 -27
  137. package/types/engine/homepage.d.mts +16 -18
  138. package/types/engine/ids.d.mts +13 -13
  139. package/types/engine/index-records.d.mts +3 -3
  140. package/types/engine/index.d.mts +2 -0
  141. package/types/engine/item-compiler.d.mts +21 -5
  142. package/types/engine/item-docs.d.mts +2 -2
  143. package/types/engine/item-registry.d.mts +6 -6
  144. package/types/engine/journals.d.mts +3 -3
  145. package/types/engine/map-notes.d.mts +2 -2
  146. package/types/engine/metadata-index.d.mts +4 -4
  147. package/types/engine/note-claims.d.mts +16 -15
  148. package/types/engine/note-ids.d.mts +4 -4
  149. package/types/engine/note-package.d.mts +1 -1
  150. package/types/engine/note-renames.d.mts +3 -3
  151. package/types/engine/note-vocabulary.d.mts +9 -8
  152. package/types/engine/pack-config.d.mts +3 -3
  153. package/types/engine/pack-router.d.mts +1 -1
  154. package/types/engine/prose-config.d.mts +9 -9
  155. package/types/engine/prose-lint.d.mts +3 -4
  156. package/types/engine/region-events.d.mts +2 -2
  157. package/types/engine/retired-fields.d.mts +10 -9
  158. package/types/engine/schema-check.d.mts +11 -11
  159. package/types/engine/site-build.d.mts +18 -19
  160. package/types/engine/site-index.d.mts +3 -4
  161. package/types/engine/sql-tables.d.mts +11 -5
  162. package/types/engine/subtype-registry.d.mts +3 -3
  163. package/types/engine/system-block.d.mts +3 -3
  164. package/types/engine/web-wikilinks.d.mts +7 -7
  165. package/types/engine/wikilink-syntax.d.mts +17 -17
  166. package/types/engine/wikilinks.d.mts +13 -12
  167. package/types/hm3/actors.d.mts +1 -1
  168. package/types/hm3/document-subtypes.d.mts +1 -1
  169. package/types/hm3/items.d.mts +1 -2
  170. package/types/hm3/template-priority.d.mts +1 -1
  171. package/types/manifest.d.mts +8 -8
  172. package/types/sohl/actors.d.mts +2 -2
  173. package/types/sohl/affiliation-standings.d.mts +2 -2
  174. package/types/sohl/being-info.d.mts +2 -2
  175. package/types/sohl/document-subtypes.d.mts +1 -1
  176. package/types/sohl/items.d.mts +1 -2
  177. package/types/sohl/note-schemas.d.mts +1 -1
  178. package/MIGRATING.md +0 -608
package/manifest.mjs CHANGED
@@ -18,16 +18,13 @@
18
18
  * so there is one job here with two spellings: assemble the manifest from the
19
19
  * repository's configuration and write it into the build stage.
20
20
  *
21
- * **There is no template any more.** A manifest used to be a hand-authored
22
- * `system.template.json` that this module stamped a few fields into which
23
- * made it the one build input still written as JSON, by hand, per repository,
24
- * with no schema and nothing checking it. Worse, it declared facts the
25
- * configuration also declared: the pack list twice, in two formats, with
26
- * nothing checking that the pairs agreed. `sohl-kethira-basic` hand-maintained
27
- * its whole `module.json`, and its `download` named an older version than the
28
- * module claimed.
21
+ * **There is no template.** A `system.template.json` this module stamped a few
22
+ * fields into would be the one build input written as JSON, by hand, per
23
+ * repository, with no schema and nothing checking it and it would declare
24
+ * facts the configuration also declares, the pack list twice in two formats,
25
+ * with nothing checking that the pairs agree.
29
26
  *
30
- * So the manifest is generated (#9). Three kinds of key end up in it:
27
+ * So the manifest is generated. Three kinds of key end up in it:
31
28
  *
32
29
  * - **Declared** — the `packageBuild.manifest` block, emitted unchanged, so a
33
30
  * key Foundry adds in a later version needs no release of this package.
@@ -122,7 +119,7 @@ export function releaseUrls({ repoUrl, version, artifact }) {
122
119
  }
123
120
 
124
121
  /**
125
- * Where this release publishes its content index (#239).
122
+ * Where this release publishes its content index.
126
123
  *
127
124
  * **Pinned to this version, like `download` and unlike `manifest`.** A
128
125
  * consumer reaches this URL by reading the dependency's manifest, so the
@@ -183,7 +180,7 @@ const MANIFEST_KEY_ORDER = Object.freeze([
183
180
  /**
184
181
  * The manifest's `packs`, derived from the one pack list the build already has.
185
182
  *
186
- * The two used to be written separately `package-build.config.yaml` declared
183
+ * The two are not written separately, with `package-build.config.yaml` declaring
187
184
  * a pack's name and type, and the manifest template declared them again beside
188
185
  * a label, a path and a system id, with nothing checking that the pairs agreed.
189
186
  * They are one list now.
@@ -265,12 +262,12 @@ function namedPacks(folders, at) {
265
262
  * `styles`, `languages`), and a staged file is a different relation, checked
266
263
  * against the stage rather than against configuration. So this is the one place
267
264
  * a declaration can go stale against a value the build already computed — and
268
- * until now nothing compared them (#81).
265
+ * until now nothing compared them.
269
266
  *
270
267
  * `HarnMaster-3-FoundryVTT` shipped the consequence: its folder named four
271
268
  * packs, three of which had not existed since the compendium was consolidated,
272
269
  * and omitted `items` — 1,577 of 1,597 documents, loose in Foundry's compendium
273
- * browser, with the build reporting nothing (HM3#420).
270
+ * browser, with the build reporting nothing.
274
271
  *
275
272
  * **The two findings are not the same finding**, and giving them one severity
276
273
  * gets one of them wrong:
@@ -343,14 +340,14 @@ export function packFolderFindings({ packFolders, packs = [] }) {
343
340
  *
344
341
  * `relationships` is the one manifest block with a second reader.
345
342
  * `@heroiclands/content-build` consumes it too, and v1.8.0 added
346
- * `itemCatalog: true` as an opt-in on a declared dependency
347
- * (content-build#82): it selects that package's Item packs as a resolution
343
+ * `itemCatalog: true` as an opt-in on a declared dependency: it selects that
344
+ * package's Item packs as a resolution
348
345
  * source for the actors pass. That is an instruction to the build, not a fact
349
346
  * about the shipped package — Foundry's relationship schema does not define
350
347
  * it, and someone reading a published manifest cannot tell a build directive
351
348
  * from a declaration about what the package needs.
352
349
  *
353
- * So the block is filtered rather than copied whole (#29). The rule is the
350
+ * So the block is filtered rather than copied whole. The rule is the
354
351
  * distinction, not the name: a key listed here answers *how is this built?*,
355
352
  * and every key that survives answers *what does this package depend on?*.
356
353
  * `itemCatalog` is the first build-time key to land on a relationship and is
@@ -441,7 +438,7 @@ export function buildManifest({ config, packageJson, artifact, flags }) {
441
438
  };
442
439
  if (config.compatibility) derived.compatibility = config.compatibility;
443
440
 
444
- // `requiresSystem` is the gate half of the declare/require split (#48). It
441
+ // `requiresSystem` is the gate half of the declare/require split. It
445
442
  // emits the `relationships.systems` entry Foundry's `supportsSystem` reads,
446
443
  // reusing the `systems:` declaration rather than restating it — a second
447
444
  // transcription is free to disagree with what it copied, which is how
@@ -476,8 +473,8 @@ export function buildManifest({ config, packageJson, artifact, flags }) {
476
473
 
477
474
  const merged = { ...declared, ...derived };
478
475
 
479
- // The index every consumer resolves this package's addresses through
480
- // (#239). Written unconditionally, because a package that publishes no
476
+ // The index every consumer resolves this package's addresses through.
477
+ // Written unconditionally, because a package that publishes no
481
478
  // index is one nothing can link into — and the failure of an absent one is
482
479
  // a dead link in somebody else's build, which is exactly the kind of
483
480
  // silence this replaced the vendored manifest to end.
@@ -562,7 +559,7 @@ function reportPackFolders(findings, configFile) {
562
559
  * The declared `packFolders` is checked against the derived `packs[]` first,
563
560
  * and an unresolvable name **stops the write**: a manifest already known to
564
561
  * describe packs the package does not ship should not reach the stage, where
565
- * the next command would deploy it (#81). See {@link packFolderFindings} for
562
+ * the next command would deploy it. See {@link packFolderFindings} for
566
563
  * the rule and why its two findings carry different severities.
567
564
  *
568
565
  * @param {object} options - As {@link buildManifest}, plus where to write.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@heroiclands/package-build",
3
- "version": "20.3.0",
3
+ "version": "20.4.0",
4
4
  "description": "Shared toolchain for building and shipping a HeroicLands Foundry VTT package — content compilation, manifest, localization, staging, bundle, release and deployment.",
5
5
  "license": "GPL-3.0-or-later",
6
6
  "type": "module",
@@ -101,7 +101,6 @@
101
101
  "CHANGELOG-content-build.md",
102
102
  "CHANGELOG.md",
103
103
  "CONTENT.md",
104
- "MIGRATING.md",
105
104
  "README.md",
106
105
  "bin",
107
106
  "bundle.mjs",
package/release.mjs CHANGED
@@ -19,7 +19,7 @@
19
19
  * advertises, so a release publishes `<artifact>.zip`, the whole staged tree,
20
20
  * and `<artifact>.json` beside it, which is what an already installed package
21
21
  * re-fetches to notice a new version. A package that ships content publishes a
22
- * third: the content index other packages resolve its addresses through (#239),
22
+ * third: the content index other packages resolve its addresses through,
23
23
  * named by the `flags.metadataUrl` the manifest advertises. Every name is fixed
24
24
  * by what the manifest says, not chosen here — see `manifest.mjs`.
25
25
  *
@@ -37,7 +37,7 @@ import path from "node:path";
37
37
  // archiver 8 is pure ESM and exports **classes**, with no default export. The
38
38
  // old `import archiver from "archiver"` factory call throws at import —
39
39
  // `does not provide an export named 'default'` — which is how this repository's
40
- // release job came to fail before a single byte was written (#1683).
40
+ // release job came to fail before a single byte was written.
41
41
  import { ZipArchive } from "archiver";
42
42
 
43
43
  /**
@@ -122,7 +122,7 @@ export async function packRelease({
122
122
  }
123
123
 
124
124
  /**
125
- * Place the content index the manifest advertises beside the archive (#239).
125
+ * Place the content index the manifest advertises beside the archive.
126
126
  *
127
127
  * **The asset's name comes from the manifest, not from here.** `flags.metadataUrl`
128
128
  * is the URL every consumer fetches, so its basename is by definition the name
package/sohl/actors.mjs CHANGED
@@ -17,21 +17,21 @@
17
17
  * The machinery an actor of any system needs — the predefined-item catalogue,
18
18
  * reference translation through the system's map, embedding and its stable ids,
19
19
  * the anchored prose sections — lives in
20
- * {@link module:engine/actor-compiler}, where a second system reaches it
21
- * (#139). What is left here is SoHL's data model: the body structure and its
20
+ * {@link module:engine/actor-compiler}, where a second system reaches it.
21
+ * What is left here is SoHL's data model: the body structure and its
22
22
  * movement profiles, the attributes-and-items frontmatter that becomes embedded
23
23
  * documents, the opening mastery level a skill is baked with, and the `system`
24
24
  * block itself.
25
25
  *
26
26
  * One content type today, and the actor subtype it produces is **declared**
27
27
  * rather than assumed to be the same word: `sohl/document-subtypes.mjs` maps
28
- * `being` → `Actor` / `being`, and this pass looks it up (#79). It read
28
+ * `being` → `Actor` / `being`, and this pass looks it up. It read
29
29
  * `ACTOR_VAULT_TYPE = "being"` here and emitted `type: "being"` several hundred
30
30
  * lines below, which made the two vocabularies agree by coincidence.
31
31
  *
32
32
  * It was two content types — `character` and `creature` — which compiled to the
33
33
  * same `being` with no branch anywhere between them; they were retired in
34
- * SoHL#1580 and are now reported by `assertTypeNotRetired` in
34
+ * retired, and are reported by `assertTypeNotRetired` in
35
35
  * `engine/ids.mjs`.
36
36
  *
37
37
  * Attributes (`sohl.attributes` map) become embedded attribute items with
@@ -56,16 +56,16 @@ import {
56
56
  import { openingMasteryLevel } from "./skill-base.mjs";
57
57
  import { SystemActorCompiler, renderSection } from "../engine/actor-compiler.mjs";
58
58
  // Which Foundry Actor subtype a note's `type` compiles into. Looked up in the
59
- // system's declared map, never inferred from the type itself (#79).
59
+ // system's declared map, never inferred from the type itself.
60
60
  import { documentSubtype } from "../engine/document-subtypes.mjs";
61
61
  import { SOHL_DOCUMENT_SUBTYPES } from "./document-subtypes.mjs";
62
62
  // The note-level `sohl:` block: `sohl.system` onto the document's `system`
63
63
  // verbatim, and `sohl.img` / `sohl.effects` / `sohl.flags` overriding their
64
- // shared top-level forms for this system alone (#58).
64
+ // shared top-level forms for this system alone.
65
65
  import { blockProperty, mergeSystemData } from "../engine/system-block.mjs";
66
66
  import { readField, retiredTopLevelKey } from "../engine/field-spec.mjs";
67
67
  // The retirement window's reports, shared with the frontmatter lint so the two
68
- // cannot say different things about the same key (#305, #332).
68
+ // cannot say different things about the same key.
69
69
  import {
70
70
  legacyKeyMessage,
71
71
  locateFrontmatterKey,
@@ -76,7 +76,7 @@ import {
76
76
  * The system this pass compiles for — the block its notes write.
77
77
  *
78
78
  * Read from the map rather than spelled here, so the block name and the subtype
79
- * map are one statement (#58/#79).
79
+ * map are one statement.
80
80
  *
81
81
  * @type {string}
82
82
  */
@@ -98,7 +98,7 @@ const DEFAULT_IMG = {
98
98
  * and the note's top level and nothing else — so `data.portrait`, the position
99
99
  * the specification names and `sohl-thalorna` writes on 646 beings, was
100
100
  * invisible, and `?? defaultImg` on the next line turned every miss into the
101
- * generic person icon rather than into a complaint (#332). Going through
101
+ * generic person icon rather than into a complaint. Going through
102
102
  * {@link module:engine/field-spec.readField} is what makes the mapping table
103
103
  * executable here as it already is for HM3's `data.species`.
104
104
  *
@@ -115,7 +115,7 @@ const PORTRAIT_FIELD = Object.freeze({
115
115
  shape: "path",
116
116
  // The two empties survive, because the caller's `?? defaultImg` is what
117
117
  // tells them apart: `null` and an absent key mean "no art named, default
118
- // me", `""` means "ship blank on purpose" (#218).
118
+ // me", `""` means "ship blank on purpose".
119
119
  read: (raw) => resolveImg(raw),
120
120
  default: null,
121
121
  describe: "Path to the portrait image.",
@@ -194,7 +194,7 @@ export class Actors extends SystemActorCompiler {
194
194
  /**
195
195
  * SoHL's note-type → document-subtype map — the one declaration that says
196
196
  * which block this pass reads, which notes it claims, and what each
197
- * becomes (#79). It is also what every embedded reference is translated
197
+ * becomes. It is also what every embedded reference is translated
198
198
  * through, which is why a subclass replaces one thing and not two.
199
199
  *
200
200
  * @type {import("../engine/document-subtypes.mjs").DocumentSubtypeMap}
@@ -298,7 +298,7 @@ export class Actors extends SystemActorCompiler {
298
298
  }
299
299
 
300
300
  /**
301
- * Bake each unopened skill's opening mastery level into the document (#46).
301
+ * Bake each unopened skill's opening mastery level into the document.
302
302
  *
303
303
  * A skill whose `masteryLevelBase` is still null once the note's frontmatter
304
304
  * has been merged onto the catalogue entry is *not yet opened*, and the
@@ -352,7 +352,7 @@ export class Actors extends SystemActorCompiler {
352
352
  const id = fm.id;
353
353
  const ctx = `actor "${name}"`;
354
354
  // The document's own subtype, and the art that goes with it. Both are
355
- // looked up from the note's `type` rather than spelled here (#79).
355
+ // looked up from the note's `type` rather than spelled here.
356
356
  const subType = /** @type {string} */ (
357
357
  documentSubtype(this.constructor.documentSubtypes, fm.type, fm, {
358
358
  absPath: this.currentNote?.absPath,
@@ -365,13 +365,13 @@ export class Actors extends SystemActorCompiler {
365
365
  const { value: authoredFolder, isAddress } = folderField(fm);
366
366
  const folder = this.folderResolver(authoredFolder, { isAddress });
367
367
 
368
- // The two retiring positions a declared field may be read from (#305,
369
- // #332). **Warnings**, on the pattern every retirement in this package
368
+ // The two retiring positions a declared field may be read from.
369
+ // **Warnings**, on the pattern every retirement in this package
370
370
  // follows: the note compiles to the correct document either way, so
371
371
  // reddening a tree over one would refuse before the sweep rather than
372
- // after it. What they buy is a count — the whole reason #332 was
373
- // invisible for so long is that nothing said which position a value
374
- // had come from, and a default is indistinguishable from a miss.
372
+ // after it. What they buy is a count — without one, nothing says which
373
+ // position a value came from, and a default is indistinguishable from
374
+ // a miss.
375
375
  const portraitReports = {
376
376
  block: SYSTEM,
377
377
  onLegacyKey: (field) =>
@@ -398,25 +398,25 @@ export class Actors extends SystemActorCompiler {
398
398
  const system = {
399
399
  // The frontmatter shortcode is the actor's stable `(type, shortcode)`
400
400
  // key — and, for a being that is an archetype, its archetype
401
- // identity (the dedup/override key of the Create-dialog picker, #604).
401
+ // identity (the dedup/override key of the Create-dialog picker).
402
402
  shortcode: fm.shortcode || "",
403
403
  // Required nullable number: a priority, or `null` for a being that
404
- // is not a template (#126 / archetype contract #604). The field was
405
- // `system.archetype` until #266 / sohl#1836; the emitted key moves
404
+ // is not a template (the archetype contract). `system.archetype`
405
+ // is the legacy spelling; the emitted key moves
406
406
  // with the schema, since an undeclared `system` key is discarded at
407
407
  // construction without a warning.
408
408
  templatePriority: systemTemplatePriority(fm, ctx),
409
- // Nullish, not `||` (#218): a note that names no portrait gets the
409
+ // Nullish, not `||`: a note that names no portrait gets the
410
410
  // subtype's default, one that writes `""` ships blank on purpose.
411
411
  // Resolved through the declaration so `data.portrait` is reached at
412
- // all — see {@link PORTRAIT_FIELD} (#332).
412
+ // all — see {@link PORTRAIT_FIELD}.
413
413
  portrait: readField(PORTRAIT_FIELD, fm, portraitReports) ?? defaultImg,
414
414
  appearance: renderSection(body || "", "appearance"),
415
415
  dossier: renderSection(body || "", "dossier"),
416
416
  };
417
417
 
418
418
  // Fill `system.body` (+ the base-actor movement fields) from the being's
419
- // frontmatter, rather than embedding a corpus item (#535). The `sohl`
419
+ // frontmatter, rather than embedding a corpus item. The `sohl`
420
420
  // block mirrors `system` field-for-field: `sohl.body` nests the body
421
421
  // (`structure` / `weight` / …), with `currentMoveMedium` /
422
422
  // `movementProfiles` flat alongside it. An **incorporeal** being omits
@@ -441,14 +441,14 @@ export class Actors extends SystemActorCompiler {
441
441
  }
442
442
 
443
443
  // Whatever the note authors under `sohl.system`, at the DataModel's own
444
- // paths (#58). This pass has no field declaration, so it claims
444
+ // paths. This pass has no field declaration, so it claims
445
445
  // nothing: every authored path is the author's, and the fields above
446
446
  // are what a note that authors none still gets.
447
447
  mergeSystemData(system, fm, { block: SYSTEM });
448
448
  this.reportUndeclaredSystemData(fm, SYSTEM, "Actor", subType);
449
449
  // And what this pass wrote itself. There is no field declaration for a
450
450
  // being at all, so *every* key here is a compiler emission — including
451
- // `templatePriority` (#126), which nothing compared until #155.
451
+ // `templatePriority`, which nothing compared until.
452
452
  this.reportEmittedSystemData(system, {
453
453
  fm,
454
454
  block: SYSTEM,
@@ -462,7 +462,7 @@ export class Actors extends SystemActorCompiler {
462
462
  return {
463
463
  name,
464
464
  type: subType,
465
- // Nullish, not `||` — see the portrait above (#218).
465
+ // Nullish, not `||` — see the portrait above.
466
466
  img: resolveImg(blockProperty(fm, SYSTEM, "img")) ?? defaultImg,
467
467
  _id: id,
468
468
  system,
@@ -483,7 +483,7 @@ export class Actors extends SystemActorCompiler {
483
483
  ownership: { default: 0 },
484
484
  // Whatever the note authors, and nothing else. The priority used to
485
485
  // be spliced in here as `flags.sohl.docArchetype`; it is a schema
486
- // field now and sits in `system` (#126).
486
+ // field now and sits in `system`.
487
487
  flags: blockProperty(fm, SYSTEM, "flags", {}),
488
488
  _stats: this.stats,
489
489
  _key: `!actors!${id}`,
@@ -13,12 +13,12 @@
13
13
 
14
14
  /**
15
15
  * The affiliation standings an authored `relation` map may use — one
16
- * affiliation's stance toward another (#1404).
16
+ * affiliation's stance toward another.
17
17
  *
18
18
  * Plain ESM for the same reason `./default-item-art.mjs` is: the pack scripts
19
19
  * run under bare `node`, so they cannot read the runtime's TypeScript
20
20
  * `AFFILIATION_STANDING`. This module is where the pipeline reads the list
21
- * from, rather than restating it inside a compiler (#1510).
21
+ * from, rather than restating it inside a compiler.
22
22
  *
23
23
  * The runtime keeps its own `defineType("SOHL.Affiliation.Standing", { … })`
24
24
  * declaration in `src/utils/constants.ts`, because that literal is *parsed out
@@ -24,9 +24,9 @@
24
24
  * **It lives here because it was living in two places.** Both
25
25
  * `Song-of-Heroic-Lands-FoundryVTT` and `sohl-thalorna` carried a copy, and the
26
26
  * copies drifted: SoHL's caller still gated the derivation on `character` and
27
- * `creature`, the two types #1580 merged into `being`, so it had matched
27
+ * `creature`, the two legacy spellings of `being`, so it had matched
28
28
  * nothing since the merge and all 95 of its being pages published with empty
29
- * sidebar sections (SoHL#1696). thalorna's copy checked `being` and was right.
29
+ * sidebar sections. thalorna's copy checked `being` and was right.
30
30
  * Nothing failed in either repository; the pages built and shipped.
31
31
  *
32
32
  * {@link isBeing} exists for that reason. The bug was not in the derivation —
@@ -36,14 +36,14 @@
36
36
  * @module
37
37
  */
38
38
 
39
- // The retirement window for a renamed note type (#78): an embedded reference
39
+ // The retirement window for a renamed note type: an embedded reference
40
40
  // still spelling `armorgear` names the same gear group as `armor`.
41
41
  import { currentType } from "../engine/ids.mjs";
42
42
 
43
43
  /**
44
44
  * The note `type` whose pages carry a being info block.
45
45
  *
46
- * One name, since #1580 merged `character` and `creature` into the `being` they
46
+ * One name: `character` and `creature` are the `being` they
47
47
  * had always compiled into. The retired names are deliberately **not** accepted
48
48
  * as aliases: they throw elsewhere in the system, and tolerating them here
49
49
  * would hide the next drift of this kind rather than surface it.
@@ -68,7 +68,7 @@ export function isBeing(fm) {
68
68
  * added in a single place rather than in each consumer's site build.
69
69
  *
70
70
  * Keyed by **note** type, which is what a being's embedded `(type, shortcode)`
71
- * references spell — and since #78 three of those are no longer the document
71
+ * references spell — and three of those are not the document
72
72
  * subtype they compile into. A reference still on a renamed spelling is
73
73
  * normalised at the lookup below rather than given a second row here.
74
74
  *
@@ -27,15 +27,15 @@
27
27
  * runtime can both import it. A `.ts` module could not be required by the build
28
28
  * scripts (they run under bare `node`, without the bundler that resolves the
29
29
  * `@src` alias and strips types). Keeping one map here is what prevents the
30
- * build-time and runtime defaults from drifting apart (issue #932 was exactly
30
+ * build-time and runtime defaults from drifting apart (which is exactly
31
31
  * that drift: the builder had a default, runtime did not).
32
32
  *
33
33
  * It lives in this package rather than in the system's `src/` tree because the
34
- * pack pipeline is installed as a dependency (#1501): a relative path out of
34
+ * pack pipeline is installed as a dependency: a relative path out of
35
35
  * the package would resolve to garbage once the pipeline runs from
36
36
  * `node_modules`. The runtime imports it back through the package's
37
- * `./sohl/default-item-art` entry point, so there is still exactly one map
38
- * (#1510). Injecting the map through configuration instead would re-open #932,
37
+ * `./sohl/default-item-art` entry point, so there is still exactly one map.
38
+ * Injecting the map through configuration instead would re-open that drift,
39
39
  * because the two sides would once more be free to disagree.
40
40
  *
41
41
  * Paths are fully resolved (`systems/sohl/...`) — the served path both layers
@@ -44,7 +44,7 @@
44
44
  * **The keys are SoHL *document* subtypes, not markdown note types.** The
45
45
  * runtime reads this with `itemData.type`, which is a Foundry Item subtype, and
46
46
  * that is the vocabulary a compendium document carries. The two vocabularies
47
- * were the same string until #78 renamed three note types (`armorgear` →
47
+ * would be the same string but for three renamed note types (`armorgear` →
48
48
  * `armor`, and its two siblings), and this map stayed on the document side
49
49
  * because that is the side the runtime cannot translate: `sohl/item-builders.mjs`
50
50
  * asks SoHL's own note-type → subtype map before it looks art up here, so the
@@ -13,11 +13,11 @@
13
13
 
14
14
  /**
15
15
  * **SoHL's note-type → document-subtype map** — which Foundry document, and
16
- * which subtype of it, a note of each content type compiles into (#79).
16
+ * which subtype of it, a note of each content type compiles into.
17
17
  *
18
18
  * The mechanism is `engine/document-subtypes.mjs`; what a *game system* does
19
19
  * with it is here, which is the `engine/` ÷ `sohl/` line this package draws
20
- * everywhere else (#36). A second system declares its own map in its own half
20
+ * everywhere else. A second system declares its own map in its own half
21
21
  * and shares nothing but the mechanism.
22
22
  *
23
23
  * **Every row is written out, identity rows included.** `skill → skill` looks
@@ -31,7 +31,7 @@
31
31
  * **Three rows are no longer the identity, and that is what the map was for.**
32
32
  * `armor`, `concoction` and `projectile` were renamed from the `…gear`
33
33
  * spellings that named SoHL's *document* subtype rather than the thing the note
34
- * is about (#78); the subtypes themselves did not move, so those three rows now
34
+ * is about; the subtypes themselves did not move, so those three rows now
35
35
  * say two different words where they used to say one twice. Landing the rename
36
36
  * cost exactly what having the map first promised it would: a data change on
37
37
  * three lines here, and no mechanism change anywhere.
@@ -40,7 +40,7 @@
40
40
  * before this map is consulted — so a tree that has not swept its 30,741
41
41
  * embedded `(type, shortcode)` references compiles byte-identically. `weapon`
42
42
  * is deliberately **not** among them: both systems call that document a
43
- * `weapongear`, so the name says nothing SoHL-specific and #78 left it alone.
43
+ * `weapongear`, so the name says nothing SoHL-specific and is left alone.
44
44
  *
45
45
  * **What this map is not.** It says which document a note becomes, never what
46
46
  * that document contains: the `system` block comes from the item registry's
@@ -59,7 +59,7 @@ import { defineDocumentSubtypes } from "../engine/document-subtypes.mjs";
59
59
  *
60
60
  * The Item rows are the thirteen types the item registry declares; the one
61
61
  * Actor row is `being`, which was two types (`character` and `creature`)
62
- * compiling to the same actor until they were retired in SoHL#1580. Types this
62
+ * compiling to the same actor before they were retired. Types this
63
63
  * map does not name — `doc`, `macro`, the three map types — compile into
64
64
  * documents that carry no system subtype at all, so they have no row and never
65
65
  * needed one.
package/sohl/index.mjs CHANGED
@@ -16,7 +16,7 @@
16
16
  * Lands data model that a generic content module must never receive.
17
17
  *
18
18
  * The item-type registry and its builders, the items and actors compilers, the
19
- * default-art map, and the affiliation standings live here (#1512). Nothing in
19
+ * default-art map, and the affiliation standings live here. Nothing in
20
20
  * `@heroiclands/package-build/engine` exports any of it, so an adventure module
21
21
  * that builds journals, macros, and scenes never receives `buildWeaponGear`.
22
22
  *
@@ -33,7 +33,7 @@
33
33
  /** The item-type registry: every type that compiles into an Item, and its builder. */
34
34
  export * as itemBuilders from "./item-builders.mjs";
35
35
 
36
- /** This system's note-type → document-subtype map, identity rows included (#79). */
36
+ /** This system's note-type → document-subtype map, identity rows included. */
37
37
  export * as documentSubtypes from "./document-subtypes.mjs";
38
38
 
39
39
  /** The Item compiler. */
@@ -47,7 +47,7 @@ export * as kbPasses from "./kb-passes.mjs";
47
47
 
48
48
  // Flat as well as namespaced: the Foundry runtime imports these by name through
49
49
  // their own entry points, and they were this barrel's surface before the
50
- // compilers arrived (#1510).
50
+ // compilers arrived.
51
51
  export { DEFAULT_ITEM_ART, defaultItemArt } from "./default-item-art.mjs";
52
52
  export { AFFILIATION_STANDINGS } from "./affiliation-standings.mjs";
53
53
  export { BEING_TYPE, GEAR_TYPE_TO_KEY, deriveBeingInfo, isBeing } from "./being-info.mjs";
@@ -18,20 +18,20 @@
18
18
  * There is one list, not two. This repository hands {@link ITEM_BUILDERS} to
19
19
  * the build as `itemBuilders` in `package-build.config.yaml`, and `itemTypes()`
20
20
  * — the whitelist — is derived from that table's own keys, so a type cannot be
21
- * whitelisted for compilation without a builder to compile it. Previously the
21
+ * whitelisted for compilation without a builder to compile it. Split, the
22
22
  * whitelist and the builder table were maintained by hand and had already
23
- * drifted: `trait` — an item type **retired in #651**, absent from
23
+ * drifted: `trait` — a **retired** item type, absent from
24
24
  * `documentTypes.Item` and reported by world migration as unrecognized — was
25
25
  * still advertised as compilable, so a `type: trait` note passed the gate and
26
26
  * then died on `BUILDERS[type] is not a function`, swallowed as a per-file
27
- * error (#1504).
27
+ * error.
28
28
  *
29
29
  * **The builders are generated, not written.** Each type's `system` builder
30
30
  * comes from its field declaration in `item-fields.mjs` by way of
31
31
  * {@link buildFromFields}, so the vocabulary a note may write is readable data
32
32
  * rather than statements buried in a function body — which is what lets the
33
- * authoring reference be generated and a note be linted against its type
34
- * (#22). One consequence worth naming: the registry's keys are now
33
+ * authoring reference be generated and a note be linted against its type.
34
+ * One consequence worth naming: the registry's keys are now
35
35
  * {@link ITEM_FIELDS}'s keys, so adding an item type is one edit *there* (plus
36
36
  * its `documentTypes.Item` declaration and its default art), and removing one
37
37
  * is likewise a single deletion.
@@ -43,7 +43,7 @@
43
43
  * own evaluation. The table travels into configuration; the engine's
44
44
  * `item-registry.mjs` reads it back out and the Item compiler dispatches
45
45
  * through that, which is how a consumer's own table is the one its notes
46
- * compile with (#1563).
46
+ * compile with.
47
47
  */
48
48
 
49
49
  import { defaultItemArt } from "./default-item-art.mjs";
@@ -86,7 +86,7 @@ const FINALIZERS = Object.freeze({
86
86
  *
87
87
  * **The art map is keyed by the document subtype**, which the runtime reads
88
88
  * with a Foundry `Item`'s own `type`, so this asks SoHL's map what an `armor`
89
- * note becomes before looking art up (#78). Translating on the build side is
89
+ * note becomes before looking art up. Translating on the build side is
90
90
  * the only place it can happen: the runtime has no note in hand. Every SoHL
91
91
  * Item row is one-to-one, so `documentSubtype` needs no frontmatter and cannot
92
92
  * throw for a discriminator.
@@ -17,8 +17,8 @@
17
17
  * This is the authority for what an item note may write, and — because
18
18
  * {@link buildFromFields} turns each list into the builder that runs — it is
19
19
  * the same authority the compiler obeys. A field that is not here is not
20
- * emitted; a description here is a description of the thing that executes
21
- * (#22). The per-type authoring reference on the knowledgebase is generated
20
+ * emitted; a description here is a description of the thing that executes.
21
+ * The per-type authoring reference on the knowledgebase is generated
22
22
  * from this file.
23
23
  *
24
24
  * **SoHL type vocabulary, so it lives in `sohl/`.** `engine/` holds the
@@ -197,7 +197,7 @@ const STRIKE_MODES = Object.freeze({
197
197
  * depends on it.
198
198
  *
199
199
  * Authored `impact.die`, stored `impactBase.die` — the one re-reading field
200
- * whose two positions are spelled differently, so both are named (#126).
200
+ * whose two positions are spelled differently, so both are named.
201
201
  *
202
202
  * @param {object} fm - The note's frontmatter.
203
203
  * @returns {number} The die size, `0` when the projectile declares none.
@@ -340,8 +340,7 @@ export const ITEM_FIELDS = Object.freeze({
340
340
  },
341
341
  {
342
342
  // Plural because the field holds a map of many standings, one per
343
- // affiliation — the singular was a misnomer every author read past
344
- // (SoHL#1781).
343
+ // affiliation — the singular reads as a misnomer.
345
344
  name: "relations",
346
345
  to: "relations",
347
346
  ...RELATION,
@@ -448,7 +447,7 @@ export const ITEM_FIELDS = Object.freeze({
448
447
  describe:
449
448
  "What running the course to the end does to the host: `death`, or the benign default `cured`.",
450
449
  },
451
- // The two **authored** thirds of each timed-phase triplet (#329). Every
450
+ // The two **authored** thirds of each timed-phase triplet. Every
452
451
  // one omits its key when the note does not carry it, because the value
453
452
  // that stands otherwise is the DataModel's `initial: null` — writing a
454
453
  // compile-time `null` over it would say "this phase takes no time",
@@ -513,7 +512,7 @@ export const ITEM_FIELDS = Object.freeze({
513
512
  "The resolution interval in seconds, standing in for a roll of the formula. Omitted when unset.",
514
513
  },
515
514
  // The `…Date` third of every timed-phase triplet, declared as **runtime
516
- // state** (#330). A phase is authored as its `…DurationFormula`; the
515
+ // state**. A phase is authored as its `…DurationFormula`; the
517
516
  // `…DurationBase` records what that rolled to; the date records *when
518
517
  // it happened*, and only play can know that. All four are
519
518
  // `worldTimeDateField()`s in SoHL's schema — nullable rather than
@@ -949,7 +948,7 @@ export const ITEM_FIELDS = Object.freeze({
949
948
  default: null,
950
949
  describe: "Shortcode of the body location injured. Unset on a descriptive condition.",
951
950
  },
952
- // A trauma's three timed phases (#329). Its healing check and course
951
+ // A trauma's three timed phases. Its healing check and course
953
952
  // both fall back to a **world setting** when the trauma sets neither
954
953
  // half, which is the sharper reason these omit rather than default: a
955
954
  // compile-time `null` written here is still a value, and the seeding in
@@ -1007,7 +1006,7 @@ export const ITEM_FIELDS = Object.freeze({
1007
1006
  describe:
1008
1007
  "The course-test interval in seconds, standing in for a roll of the formula. Omitted when unset.",
1009
1008
  },
1010
- // Runtime state, for the reason `affliction`'s four are (#330): a
1009
+ // Runtime state, for the reason `affliction`'s four are: a
1011
1010
  // trauma's dates are crystallized when the phase fires, and world time
1012
1011
  // does not exist while content is compiled.
1013
1012
  {