@heroiclands/package-build 20.3.1 → 20.5.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 (195) hide show
  1. package/CHANGELOG.md +351 -0
  2. package/CONTENT.md +322 -110
  3. package/README.md +21 -10
  4. package/bin/content-build.mjs +204 -92
  5. package/bin/package-build.mjs +48 -15
  6. package/config.mjs +6 -8
  7. package/content-config.mjs +518 -151
  8. package/docs/api.md +1352 -0
  9. package/docs/commands.md +1609 -0
  10. package/docs/configuration.md +1432 -0
  11. package/docs/content-format.md +73 -74
  12. package/docs/diagnostics.md +356 -0
  13. package/docs/getting-started.md +813 -0
  14. package/docs/project-setup.md +469 -0
  15. package/e2e.mjs +4 -4
  16. package/engine/actor-compiler.mjs +64 -61
  17. package/engine/address-charset.mjs +6 -6
  18. package/engine/address-diff.mjs +57 -52
  19. package/engine/anchored-sections.mjs +1 -1
  20. package/engine/anchors.mjs +1 -1
  21. package/engine/base-compiler.mjs +42 -38
  22. package/engine/bundle-notes.mjs +4 -4
  23. package/engine/bundles.mjs +17 -8
  24. package/engine/code-fences.mjs +3 -3
  25. package/engine/compendiums.mjs +8 -8
  26. package/engine/compile-corpus.mjs +4 -5
  27. package/engine/content-address.mjs +24 -24
  28. package/engine/content-charset.mjs +1 -1
  29. package/engine/content-format-check.mjs +24 -25
  30. package/engine/content-format.mjs +8 -8
  31. package/engine/content-html.mjs +202 -0
  32. package/engine/content-icons.mjs +196 -165
  33. package/engine/content-index.mjs +61 -40
  34. package/engine/content-links.mjs +74 -41
  35. package/engine/content-lint.mjs +64 -34
  36. package/engine/content-package.mjs +7 -9
  37. package/engine/content-slug.mjs +2 -2
  38. package/engine/content-tables.mjs +38 -34
  39. package/engine/content-tree.mjs +1 -1
  40. package/engine/derived-fields.mjs +174 -0
  41. package/engine/diagnostics.mjs +3 -4
  42. package/engine/document-subtypes.mjs +6 -7
  43. package/engine/field-reference.mjs +8 -8
  44. package/engine/field-spec.mjs +29 -30
  45. package/engine/folder-notes.mjs +18 -16
  46. package/engine/foreign-catalog.mjs +8 -9
  47. package/engine/foundry-entries.mjs +19 -20
  48. package/engine/frontmatter-lint.mjs +95 -103
  49. package/engine/frontmatter.mjs +11 -11
  50. package/engine/generate.mjs +44 -39
  51. package/engine/helpers.mjs +147 -84
  52. package/engine/homepage.mjs +20 -22
  53. package/engine/ids.mjs +15 -15
  54. package/engine/index-records.mjs +4 -4
  55. package/engine/index.mjs +26 -10
  56. package/engine/item-compiler.mjs +54 -29
  57. package/engine/item-docs.mjs +11 -13
  58. package/engine/item-registry.mjs +13 -13
  59. package/engine/journals.mjs +24 -15
  60. package/engine/macros.mjs +3 -3
  61. package/engine/map-notes.mjs +6 -6
  62. package/engine/metadata-index.mjs +5 -5
  63. package/engine/note-claims.mjs +51 -41
  64. package/engine/note-ids.mjs +5 -5
  65. package/engine/note-package.mjs +4 -4
  66. package/engine/note-renames.mjs +3 -3
  67. package/engine/note-schemas.mjs +3 -8
  68. package/engine/note-vocabulary.mjs +56 -54
  69. package/engine/pack-config.mjs +39 -25
  70. package/engine/pack-router.mjs +0 -0
  71. package/engine/pdf-build.mjs +464 -0
  72. package/engine/pdf-fonts.mjs +420 -0
  73. package/engine/pdf-render.mjs +798 -0
  74. package/engine/pdf-toc.mjs +525 -0
  75. package/engine/prose-config.mjs +9 -9
  76. package/engine/prose-lint.mjs +12 -13
  77. package/engine/region-events.mjs +2 -2
  78. package/engine/retired-fields.mjs +24 -22
  79. package/engine/runtime-only-fields.mjs +1 -1
  80. package/engine/scene-levels.mjs +1 -1
  81. package/engine/scenes.mjs +33 -25
  82. package/engine/schema-check.mjs +21 -21
  83. package/engine/schema-extract.mjs +1 -1
  84. package/engine/site-build.mjs +66 -50
  85. package/engine/site-index.mjs +17 -18
  86. package/engine/sql-tables.mjs +21 -13
  87. package/engine/subtype-registry.mjs +5 -4
  88. package/engine/system-block.mjs +18 -19
  89. package/engine/systems.mjs +2 -2
  90. package/engine/web-wikilinks.mjs +41 -38
  91. package/engine/wikilink-syntax.mjs +16 -16
  92. package/engine/wikilinks.mjs +40 -42
  93. package/hm3/actors.mjs +30 -22
  94. package/hm3/document-subtypes.mjs +5 -5
  95. package/hm3/index.mjs +2 -2
  96. package/hm3/item-builders.mjs +1 -1
  97. package/hm3/item-fields.mjs +3 -3
  98. package/hm3/items.mjs +28 -8
  99. package/hm3/template-priority.mjs +2 -2
  100. package/lang.mjs +3 -3
  101. package/manifest.mjs +17 -20
  102. package/package.json +1 -2
  103. package/release.mjs +66 -6
  104. package/sohl/actors.mjs +36 -28
  105. package/sohl/affiliation-standings.mjs +2 -2
  106. package/sohl/being-info.mjs +5 -5
  107. package/sohl/default-item-art.mjs +5 -5
  108. package/sohl/document-subtypes.mjs +5 -5
  109. package/sohl/index.mjs +3 -3
  110. package/sohl/item-builders.mjs +7 -7
  111. package/sohl/item-fields.mjs +8 -9
  112. package/sohl/items.mjs +28 -6
  113. package/sohl/kb-passes.mjs +5 -5
  114. package/sohl/note-schemas.mjs +12 -12
  115. package/sohl/skill-base.mjs +1 -1
  116. package/types/content-config.d.mts +91 -39
  117. package/types/e2e.d.mts +3 -3
  118. package/types/engine/actor-compiler.d.mts +45 -40
  119. package/types/engine/address-charset.d.mts +6 -6
  120. package/types/engine/address-diff.d.mts +60 -6
  121. package/types/engine/base-compiler.d.mts +27 -21
  122. package/types/engine/bundle-notes.d.mts +3 -3
  123. package/types/engine/bundles.d.mts +10 -1
  124. package/types/engine/code-fences.d.mts +3 -3
  125. package/types/engine/compendiums.d.mts +3 -3
  126. package/types/engine/compile-corpus.d.mts +1 -1
  127. package/types/engine/content-address.d.mts +20 -20
  128. package/types/engine/content-format-check.d.mts +6 -6
  129. package/types/engine/content-format.d.mts +2 -2
  130. package/types/engine/content-html.d.mts +78 -0
  131. package/types/engine/content-icons.d.mts +139 -92
  132. package/types/engine/content-index.d.mts +59 -15
  133. package/types/engine/content-links.d.mts +8 -8
  134. package/types/engine/content-lint.d.mts +8 -6
  135. package/types/engine/content-package.d.mts +6 -8
  136. package/types/engine/content-tables.d.mts +49 -18
  137. package/types/engine/derived-fields.d.mts +101 -0
  138. package/types/engine/diagnostics.d.mts +2 -2
  139. package/types/engine/document-subtypes.d.mts +3 -3
  140. package/types/engine/field-spec.d.mts +37 -39
  141. package/types/engine/folder-notes.d.mts +4 -5
  142. package/types/engine/foreign-catalog.d.mts +3 -3
  143. package/types/engine/foundry-entries.d.mts +6 -7
  144. package/types/engine/frontmatter-lint.d.mts +10 -9
  145. package/types/engine/frontmatter.d.mts +7 -7
  146. package/types/engine/generate.d.mts +7 -7
  147. package/types/engine/helpers.d.mts +128 -56
  148. package/types/engine/homepage.d.mts +16 -18
  149. package/types/engine/ids.d.mts +13 -13
  150. package/types/engine/index-records.d.mts +3 -3
  151. package/types/engine/index.d.mts +6 -0
  152. package/types/engine/item-compiler.d.mts +21 -5
  153. package/types/engine/item-docs.d.mts +2 -2
  154. package/types/engine/item-registry.d.mts +6 -6
  155. package/types/engine/journals.d.mts +12 -3
  156. package/types/engine/map-notes.d.mts +2 -2
  157. package/types/engine/metadata-index.d.mts +4 -4
  158. package/types/engine/note-claims.d.mts +30 -22
  159. package/types/engine/note-ids.d.mts +4 -4
  160. package/types/engine/note-package.d.mts +1 -1
  161. package/types/engine/note-renames.d.mts +3 -3
  162. package/types/engine/note-vocabulary.d.mts +31 -203
  163. package/types/engine/pack-config.d.mts +7 -7
  164. package/types/engine/pack-router.d.mts +1 -1
  165. package/types/engine/pdf-build.d.mts +42 -0
  166. package/types/engine/pdf-fonts.d.mts +30 -0
  167. package/types/engine/pdf-render.d.mts +144 -0
  168. package/types/engine/pdf-toc.d.mts +114 -0
  169. package/types/engine/prose-config.d.mts +9 -9
  170. package/types/engine/prose-lint.d.mts +3 -4
  171. package/types/engine/region-events.d.mts +2 -2
  172. package/types/engine/retired-fields.d.mts +10 -9
  173. package/types/engine/scenes.d.mts +10 -1
  174. package/types/engine/schema-check.d.mts +13 -13
  175. package/types/engine/site-build.d.mts +52 -25
  176. package/types/engine/site-index.d.mts +3 -4
  177. package/types/engine/sql-tables.d.mts +11 -5
  178. package/types/engine/subtype-registry.d.mts +3 -3
  179. package/types/engine/system-block.d.mts +3 -3
  180. package/types/engine/web-wikilinks.d.mts +7 -7
  181. package/types/engine/wikilink-syntax.d.mts +17 -17
  182. package/types/engine/wikilinks.d.mts +14 -14
  183. package/types/hm3/actors.d.mts +9 -1
  184. package/types/hm3/document-subtypes.d.mts +1 -1
  185. package/types/hm3/items.d.mts +9 -2
  186. package/types/hm3/template-priority.d.mts +1 -1
  187. package/types/manifest.d.mts +8 -8
  188. package/types/release.d.mts +15 -4
  189. package/types/sohl/actors.d.mts +12 -4
  190. package/types/sohl/affiliation-standings.d.mts +2 -2
  191. package/types/sohl/being-info.d.mts +2 -2
  192. package/types/sohl/document-subtypes.d.mts +1 -1
  193. package/types/sohl/items.d.mts +9 -2
  194. package/types/sohl/note-schemas.d.mts +1 -1
  195. package/MIGRATING.md +0 -608
@@ -34,7 +34,7 @@ export function deepMerge(base: any, overlay: any): any;
34
34
  * vocabulary, so a reference is translated forward through the system's map
35
35
  * before it reaches this function; see
36
36
  * {@link SystemActorCompiler#embeddedSubtype} for why the translation goes that
37
- * way and not the other (#140).
37
+ * way and not the other.
38
38
  *
39
39
  * @param {string} subType - The Foundry Item subtype.
40
40
  * @param {string} shortcode - The item's `system.shortcode`.
@@ -43,7 +43,7 @@ export function deepMerge(base: any, overlay: any): any;
43
43
  export function itemAddress(subType: string, shortcode: string): string;
44
44
  /**
45
45
  * The key one predefined item is held under **for the package that publishes
46
- * it** — the address a `model:` naming that package resolves through (#334).
46
+ * it** — the address a `model:` naming that package resolves through.
47
47
  *
48
48
  * The unqualified {@link itemAddress} stays beside it, and the two answer
49
49
  * different questions. A `model` that names no package means *this* one and
@@ -70,11 +70,12 @@ export function packagedItemAddress(pkg: string, subType: string, shortcode: str
70
70
  * A shortcode is case-sensitive and routinely mixed — `Clb`, `LtShoe`,
71
71
  * `HsTunic` — while an **address** is not: `readQualifier` normalises what it
72
72
  * reads, and every canonical address is lowercase. So the moment a `model:` is
73
- * read as an address (#334), `weapongear-clb` has to find the document whose
74
- * `system.shortcode` is `Clb`, and an exact match cannot (#346).
73
+ * read as an address, `weapongear-clb` has to find the document whose
74
+ * `system.shortcode` is `Clb`, and an exact match cannot.
75
75
  *
76
76
  * Folding is safe because the fold is already the address: no two items in any
77
- * published tree differ only by the case of their shortcode, and #340 will make
77
+ * published tree differ only by the case of their shortcode, and the rule
78
+ * makes
78
79
  * that impossible rather than merely true.
79
80
  *
80
81
  * **This is not {@link itemAddress}, and must not become it.** That one seeds
@@ -116,13 +117,13 @@ export function embeddedIdentity(item: object): string;
116
117
  * four corpora holds 180 items, at which 64 bits collide with probability
117
118
  * around 10⁻¹⁵.
118
119
  *
119
- * **It takes no index** (#268). Keying on a position meant reordering a being's
120
+ * **It takes no index**. Keying on a position meant reordering a being's
120
121
  * item list renumbered every id after the change, so a re-import created new
121
122
  * documents beside the old ones — while nothing about those documents had
122
123
  * changed, only their neighbours. The identity always exists or must be stated;
123
124
  * see {@link embeddedIdentity}.
124
125
  *
125
- * Keyed by the **document subtype**, so renaming a note type (#78) leaves every
126
+ * Keyed by the **document subtype**, so renaming a note type leaves every
126
127
  * embedded id where it was.
127
128
  *
128
129
  * @param {string} actorId - The owning actor's id.
@@ -186,7 +187,7 @@ export class SystemActorCompiler extends BasePackCompiler {
186
187
  foreignSourceDirs: any;
187
188
  /**
188
189
  * Every package a `model:` may name besides this one — the dependencies
189
- * whose item catalogues were supplied (#334).
190
+ * whose item catalogues were supplied.
190
191
  *
191
192
  * @returns {Set<string>} The dependency package ids.
192
193
  */
@@ -210,7 +211,7 @@ export class SystemActorCompiler extends BasePackCompiler {
210
211
  * The Foundry Item subtype an embedded reference's `type` addresses.
211
212
  *
212
213
  * **The reference is in the note vocabulary; the address is in the
213
- * document's** (#140). An actor writes `(type, shortcode)` with the type an
214
+ * document's**. An actor writes `(type, shortcode)` with the type an
214
215
  * author authors, while {@link itemAddress} keys the predefined items by
215
216
  * the subtype each compiled document carries — so exactly one of the two
216
217
  * sides has to translate, and it is this one. The system's map is a
@@ -223,6 +224,31 @@ export class SystemActorCompiler extends BasePackCompiler {
223
224
  * subtype, or why the reference names none.
224
225
  */
225
226
  embeddedSubtype(type: string): import("./document-subtypes.mjs").ReferencedSubtype;
227
+ /**
228
+ * Read an entry's `model:` — the address of the item it is a copy of.
229
+ *
230
+ * The address grammar is the wikilink one, so a `model` is written at
231
+ * whatever length says what it means: `skill-wpnc` within this package,
232
+ * `sohl-sohl-skill-wpnc` to reach another. The system segment defaults from
233
+ * the block the entry sits in — `<system>.items` — which is what makes the
234
+ * short form name an *Item* here while the same string in body prose names
235
+ * a page.
236
+ *
237
+ * It replaced a top-level `shortcode:` that meant something different from
238
+ * the `system.shortcode` beside it and could not say which package a
239
+ * template came from.
240
+ *
241
+ * @param {unknown} model - The authored value.
242
+ * @param {number} index - The entry's position, for the message.
243
+ * @param {string} ctx - Diagnostic context (the actor's label).
244
+ * @returns {{type: string, shortcode: string, package: string|null}|null}
245
+ * The parsed address, or `null` after reporting why it is not one.
246
+ */
247
+ readModel(model: unknown, index: number, ctx: string): {
248
+ type: string;
249
+ shortcode: string;
250
+ package: string | null;
251
+ } | null;
226
252
  /**
227
253
  * Resolve one embedded item from a `(type, shortcode?, overlay)`
228
254
  * descriptor. If `shortcode` is given, the predefined item is fetched
@@ -230,7 +256,7 @@ export class SystemActorCompiler extends BasePackCompiler {
230
256
  * descriptor must carry enough fields to stand alone. The embedded
231
257
  * item's `_id` is regenerated deterministically from
232
258
  * `(actorId, subType, shortcode, indexKey)` so re-exports are stable —
233
- * from the **document subtype**, so that renaming a note type (#78) leaves
259
+ * from the **document subtype**, so that renaming a note type leaves
234
260
  * every embedded id exactly where it was.
235
261
  * Returns null if the descriptor cannot be resolved.
236
262
  *
@@ -239,45 +265,24 @@ export class SystemActorCompiler extends BasePackCompiler {
239
265
  * @param {string} type - The **note** type the reference names.
240
266
  * @param {string|null} shortcode - The referenced item's shortcode, or
241
267
  * `null` for a stand-alone entry.
242
- * @param {object} [overlay] - The entry's remaining properties.
268
+ * @param {object} overlay - The entry's remaining properties.
243
269
  * @param {string} indexKey - Where the reference sits, for a diagnostic.
244
- * It no longer reaches the id (#268) it names the entry in a message.
270
+ * It names the entry in a message and does not reach the id.
245
271
  * @param {string} ctx - Diagnostic context (the actor's label).
246
272
  * @param {object} [at] - Where to locate a finding.
247
273
  * @param {string} [at.fmKey] - The frontmatter key the reference sits
248
274
  * under, so an unresolved one is reported at the reference rather than
249
275
  * at the note.
276
+ * @param {string|null} [at.modelPackage] - The package a `model:` names,
277
+ * where the template comes from another package's catalogue. Given one,
278
+ * the packaged address is what resolves and nothing local shadows it.
250
279
  * @returns {object|null} The embedded item, or null when it resolved to
251
280
  * nothing — always with a finding emitted.
252
281
  */
253
- /**
254
- * Read an entry's `model:` — the address of the item it is a copy of.
255
- *
256
- * The address grammar is the wikilink one (#336), so a `model` is written at
257
- * whatever length says what it means: `skill-wpnc` within this package,
258
- * `sohl-sohl-skill-wpnc` to reach another. The system segment defaults from
259
- * the block the entry sits in — `<system>.items` — which is what makes the
260
- * short form name an *Item* here while the same string in body prose names
261
- * a page.
262
- *
263
- * It replaced a top-level `shortcode:` that meant something different from
264
- * the `system.shortcode` beside it and could not say which package a
265
- * template came from (#334).
266
- *
267
- * @param {unknown} model - The authored value.
268
- * @param {number} index - The entry's position, for the message.
269
- * @param {string} ctx - Diagnostic context (the actor's label).
270
- * @returns {{type: string, shortcode: string, package: string|null}|null}
271
- * The parsed address, or `null` after reporting why it is not one.
272
- */
273
- readModel(model: unknown, index: number, ctx: string): {
274
- type: string;
275
- shortcode: string;
276
- package: string | null;
277
- } | null;
278
- resolveEmbedded(itemsMap: any, actorId: any, type: any, shortcode: any, overlay: any, indexKey: any, ctx: any, { fmKey, modelPackage }?: {
279
- modelPackage?: null | undefined;
280
- }): any;
282
+ resolveEmbedded(itemsMap: Map<string, object>, actorId: string, type: string, shortcode: string | null, overlay: object, indexKey: string, ctx: string, { fmKey, modelPackage }?: {
283
+ fmKey?: string | undefined;
284
+ modelPackage?: string | null | undefined;
285
+ }): object | null;
281
286
  #private;
282
287
  }
283
288
  import { BasePackCompiler } from "./base-compiler.mjs";
@@ -11,7 +11,7 @@
11
11
  */
12
12
  export function isAddressSegment(value: unknown): boolean;
13
13
  /**
14
- * The one charset every segment of a canonical address is held to (#59).
14
+ * The one charset every segment of a canonical address is held to.
15
15
  *
16
16
  * An address is a hyphen-joined tuple — `package-system-type-shortcode`, so
17
17
  * `sohl-none-doc-gear` — and it is read back by **counting segments**, with a
@@ -41,7 +41,7 @@ export function isAddressSegment(value: unknown): boolean;
41
41
  * digits only.
42
42
  *
43
43
  * Case *was* deliberately unconstrained, on the reasoning that case has no
44
- * bearing on the separator — which is true, and beside the point (#340).
44
+ * bearing on the separator — which is true, and beside the point.
45
45
  *
46
46
  * **Two names that differ only in case are two names nobody can tell apart.** A
47
47
  * shortcode is how a person names a thing when writing a reference —
@@ -53,10 +53,10 @@ export function isAddressSegment(value: unknown): boolean;
53
53
  * `sohl-sohl-weapongear-clb` and its `_id` derived from that. The authored name
54
54
  * and its address disagreed, and everything downstream keys on the address —
55
55
  * which left two notes differing only in case sharing one address, one `_id` and
56
- * one URL, with nothing to report it. It also forced two exceptions elsewhere:
57
- * #336 had to exempt the shortcode from the lowercase rule it pinned on every
58
- * other segment, and #346 had to fold the shortcode's case in the item catalogue
59
- * because an address is lowercased when read.
56
+ * one URL, with nothing to report it. It also forces two exceptions elsewhere:
57
+ * the shortcode has to be exempted from the lowercase rule pinned on every
58
+ * other segment, and its case has to be folded in the item catalogue because
59
+ * an address is lowercased when read.
60
60
  *
61
61
  * One case, one spelling, no exceptions. Every tree already complies but two,
62
62
  * and nothing in any of them collides when folded.
@@ -39,9 +39,60 @@ export function readItemAddresses(dirs: readonly string[]): Map<string, {
39
39
  shortcode: string;
40
40
  file: string;
41
41
  }>;
42
- export function declaredPredecessors(contentBase: any, { skipDirectories, maps, config, records, problems }?: {
43
- maps?: readonly import("./document-subtypes.mjs").DocumentSubtypeMap[] | undefined;
44
- }): Map<any, any>;
42
+ /**
43
+ * Every rename the tree's notes **declare**, as old address → where it went.
44
+ *
45
+ * Read from the content tree rather than from compiled output, because a
46
+ * declaration is authored and the compiled document does not carry it: nothing
47
+ * downstream consumes `renamedFrom:`, so emitting it into every pack to let one
48
+ * diagnostic read it back would put a build-time note in shipped data forever.
49
+ * The tree is already read by this module for the same reason
50
+ * ({@link noteFilesById}) — to place a finding where its author can fix it.
51
+ *
52
+ * **A declaration is keyed by document subtype, not by note type.** The address
53
+ * space is the one consumers resolve against, and it is spelled in compiled
54
+ * documents: `hm3` compiles a `projectile` note into a `missilegear` item,
55
+ * so that is the address a rename of it moves. {@link referencedSubtype} is the
56
+ * function that already answers this for a being's embedded `(type, shortcode)`
57
+ * references, so both sides read the same rule rather than a second copy of it.
58
+ *
59
+ * **An entry is emitted for every system that maps the type**, whether or not
60
+ * the note declares that system's block. Over-emitting is inert — the diff uses
61
+ * an entry only when the baseline published the old address *and* this build
62
+ * publishes the new one, and a system the note does not compile for satisfies
63
+ * neither — while asking which blocks a note declares would put a second,
64
+ * subtly different answer to that question in a third place.
65
+ *
66
+ * **First claim wins on a collision.** Two notes naming one predecessor is a
67
+ * contradiction — an address has one successor — and it is reported as an error
68
+ * by `engine/content-lint.mjs`, where both notes are in hand and can both be
69
+ * named. Picking one here keeps this a map; it is not a resolution, and nothing
70
+ * rests on which one it picked.
71
+ *
72
+ * @param {string} contentBase - Root of the content tree.
73
+ * @param {object} opts
74
+ * @param {readonly string[]} [opts.skipDirectories] - The corpus scope. Stated
75
+ * by the caller, never defaulted — see {@link addressCorpus}.
76
+ * @param {readonly object[]} [opts.maps] - The document-subtype maps.
77
+ * @param {object} [opts.config] - The resolved build configuration.
78
+ * @param {readonly object[]} [opts.records] - Index records the caller already
79
+ * derived, shared with {@link noteFilesById} so one command reads one corpus.
80
+ * @param {object[]} [opts.problems] - Collects the notes the index cannot
81
+ * record, so one of them does not abort the diff before it reports.
82
+ * @returns {Map<string, {to: string, file: string, shortcode: string}>} Old
83
+ * address → the address the declaring note publishes at now, and that note.
84
+ */
85
+ export function declaredPredecessors(contentBase: string, { skipDirectories, maps, config, records, problems }?: {
86
+ skipDirectories?: readonly string[] | undefined;
87
+ maps?: readonly object[] | undefined;
88
+ config?: object | undefined;
89
+ records?: readonly object[] | undefined;
90
+ problems?: object[] | undefined;
91
+ }): Map<string, {
92
+ to: string;
93
+ file: string;
94
+ shortcode: string;
95
+ }>;
45
96
  /**
46
97
  * Every address the baseline published that this build does not.
47
98
  *
@@ -57,7 +108,7 @@ export function declaredPredecessors(contentBase: any, { skipDirectories, maps,
57
108
  * @param {Map<string, {to: string, file: string}>} [opts.predecessors] - The
58
109
  * declared renames, from {@link declaredPredecessors}. Omitted, the diff
59
110
  * falls back to the id join alone and reports an unpinned rename as a
60
- * withdrawal, which is what it did before #278.
111
+ * withdrawal, which is what it did before.
61
112
  * @returns {Array<object>} One finding per departed address, in address order
62
113
  * so two runs read the same. `kind` is `"renamed"` (with `to`, and `declared`
63
114
  * when it was the note's word rather than an id match) or `"withdrawn"`.
@@ -85,12 +136,15 @@ export function diffItemAddresses(baseline: Map<string, object>, current: Map<st
85
136
  * id is derived against. See {@link addressCorpus} for why that matters.
86
137
  * @param {readonly object[]} [opts.records] - Index records the caller already
87
138
  * derived, shared with {@link declaredPredecessors}.
139
+ * @param {object[]} [opts.problems] - Collects the notes the index cannot
140
+ * record, so one of them does not abort the diff before it reports.
88
141
  * @returns {Map<string, string>} Document id → the note's absolute path.
89
142
  */
90
143
  export function noteFilesById(contentBase: string, { skipDirectories, config, records, problems }?: {
91
144
  skipDirectories?: readonly string[] | undefined;
92
145
  config?: object | undefined;
93
146
  records?: readonly object[] | undefined;
147
+ problems?: object[] | undefined;
94
148
  }): Map<string, string>;
95
149
  /**
96
150
  * Where to send the reader for one finding.
@@ -105,7 +159,7 @@ export function noteFilesById(contentBase: string, { skipDirectories, config, re
105
159
  * A **declared** rename knows its note without any lookup — the declaration is
106
160
  * how it was found — and is reported at the `renamedFrom:` line rather than the
107
161
  * `shortcode:` line, because that is the line the finding is about and the one
108
- * the author deletes once the declaration has done its work (#278).
162
+ * the author deletes once the declaration has done its work.
109
163
  *
110
164
  * @param {object} finding - One finding from {@link diffItemAddresses}.
111
165
  * @param {Map<string, string>} noteFiles - From {@link noteFilesById}.
@@ -126,7 +180,7 @@ export function locateAddressFinding(finding: object, noteFiles: Map<string, str
126
180
  * known — and says so, rather than leaving the reader to wonder whether one was
127
181
  * looked for.
128
182
  *
129
- * **A declared rename says it is declared** (#278). The two claims are not
183
+ * **A declared rename says it is declared**. The two claims are not
130
184
  * equally checkable: an id match is a fact in the artefacts, while a
131
185
  * declaration is an author's word, and a reader deciding whether to trust the
132
186
  * successor needs to know which one they have. Saying "the same document" of a
@@ -5,7 +5,7 @@
5
5
  * note is one this build **refused** — it declares a retired frontmatter field
6
6
  * — and it is an error; a skipped one legitimately belongs to another pass, and
7
7
  * there are thousands of those. Folding the first into the second is what let a
8
- * whole tree be filtered out in silence (#56).
8
+ * whole tree be filtered out in silence.
9
9
  *
10
10
  * @typedef {object} PassStats
11
11
  * @property {number} compiled - Notes that became a document.
@@ -13,7 +13,7 @@
13
13
  * @property {number} skippedOther - Notes this pass does not claim.
14
14
  * @property {number} declined - Notes this pack **refused** — one declaring a
15
15
  * retired frontmatter field, or one routed to a system pack whose system it
16
- * says nothing about (#58). Counted as errors, never as skips.
16
+ * says nothing about. Counted as errors, never as skips.
17
17
  */
18
18
  /**
19
19
  * The shared walk → filter → expand → convert → build → write → count loop.
@@ -51,7 +51,7 @@ export class BasePackCompiler {
51
51
  * its generated tables expanded and its wikilinks converted.
52
52
  *
53
53
  * False for a pass whose output must be exactly what the author typed —
54
- * the macros pass, whose `command` is executable source (#1514). A pass
54
+ * the macros pass, whose `command` is executable source. A pass
55
55
  * that says so also skips building the content-wide link index it would
56
56
  * never read.
57
57
  *
@@ -67,7 +67,7 @@ export class BasePackCompiler {
67
67
  * passes wrote — so an Actor pass must run after every Item pass, and it
68
68
  * says so here.
69
69
  *
70
- * The generator derives the compile order from this (#73), so the order
70
+ * The generator derives the compile order from this, so the order
71
71
  * `packs:` declares is presentation only — it is the manifest's `packs`
72
72
  * array as well, and a consumer orders that for a reader. A pass that
73
73
  * reads another's output states the dependency once, in the class that
@@ -82,7 +82,7 @@ export class BasePackCompiler {
82
82
  static readsPackOutputOf: readonly string[];
83
83
  /**
84
84
  * Whether this pass's document **is** a system's data, and therefore takes
85
- * only notes that carry that system's block (#58).
85
+ * only notes that carry that system's block.
86
86
  *
87
87
  * A pack may declare a `system:` — `harn-ensemble` ships an `actors-hm3`
88
88
  * and an `actors-sohl` from one tree — and the note-side half of that is
@@ -112,7 +112,7 @@ export class BasePackCompiler {
112
112
  * legal on every note whatever its type, because
113
113
  * `BLOCK_DOCUMENT_PROPERTIES` maps it onto `document.img` — so a note whose
114
114
  * document has no such property authors it, validates, compiles, and loses
115
- * the value with nothing said. That is #349: `Parrot` in `sohl-thalorna`
115
+ * the value with nothing said: `Parrot` in `sohl-thalorna`
116
116
  * had declared `img:` since long before the art rule existed and compiled
117
117
  * `img: null` exactly as a note declaring nothing does. Naming the fields
118
118
  * here is what lets the lint tell an inert key from a live one.
@@ -134,13 +134,19 @@ export class BasePackCompiler {
134
134
  * never descends into. Required: see {@link assertStatedScope}.
135
135
  * @param {(address: string|null) => string|null} [options.folderResolver] -
136
136
  * Resolves a `packFolder` — a folder note's address — to the Foundry
137
- * folder id it materialises as in this pack (#255, #257).
137
+ * folder id it materialises as in this pack.
138
138
  * @param {string} [options.packName] - The pack this pass writes.
139
+ * @param {string|null} [options.packSystem] - The system that pack declares,
140
+ * which decides the `_stats` it stamps and the system block a note must
141
+ * carry to reach it. `null` for a pack that declares none.
139
142
  * @param {string} [options.docType] - The Foundry document type it holds.
140
143
  * @param {{resolve: Function}} [options.router] - The pack router. Omit it
141
144
  * — as the unit suite does — and every claimed note is compiled here.
142
145
  * @param {boolean} [options.routingReporter] - Whether this pass reports a
143
146
  * note of its type that routes nowhere.
147
+ * @param {object} [options.corpus] - The corpus this compile is running
148
+ * over, derived once and shared by every pass. A pass handed none derives
149
+ * its own in `prepare`, and reports that corpus's problems itself.
144
150
  */
145
151
  constructor({ contentBase, dest, skipDirectories, folderResolver, packName, packSystem, docType, router, routingReporter, corpus, }?: {
146
152
  contentBase: string;
@@ -148,11 +154,13 @@ export class BasePackCompiler {
148
154
  skipDirectories: readonly string[];
149
155
  folderResolver?: ((address: string | null) => string | null) | undefined;
150
156
  packName?: string | undefined;
157
+ packSystem?: string | null | undefined;
151
158
  docType?: string | undefined;
152
159
  router?: {
153
160
  resolve: Function;
154
161
  } | undefined;
155
162
  routingReporter?: boolean | undefined;
163
+ corpus?: object | undefined;
156
164
  });
157
165
  /** @type {string} */
158
166
  contentBase: string;
@@ -163,7 +171,7 @@ export class BasePackCompiler {
163
171
  /** @type {number} */
164
172
  errorCount: number;
165
173
  /**
166
- * Emitted-`system` findings, one per `documentType|subtype|field` (#155).
174
+ * Emitted-`system` findings, one per `documentType|subtype|field`.
167
175
  *
168
176
  * A key the compiler writes is on **every** document of a subtype, so
169
177
  * reporting it where it is found would print the same sentence 3,126 times
@@ -219,10 +227,10 @@ export class BasePackCompiler {
219
227
  * @type {number}
220
228
  */
221
229
  unresolvedLinks: number;
222
- packSystem: any;
223
- corpus: any;
230
+ packSystem: string | null;
231
+ corpus: object | undefined;
224
232
  /**
225
- * The `_stats` block every entry this pass emits is stamped with (#48).
233
+ * The `_stats` block every entry this pass emits is stamped with.
226
234
  *
227
235
  * Per pack rather than per package, because a module may ship the same
228
236
  * content for two systems — `harn-ensemble` has an `actors-hm3` pack and an
@@ -252,8 +260,7 @@ export class BasePackCompiler {
252
260
  * routed *here* and carries nothing for this pack's system is an authoring
253
261
  * mistake with a hollow document at the end of it, not a note that belongs
254
262
  * to another pass. Skipping it quietly is how a whole tree compiles to
255
- * documents nobody can use — the failure mode #1502 and #56 are both
256
- * instances of.
263
+ * documents nobody can use.
257
264
  *
258
265
  * @param {object} fm - The note's frontmatter.
259
266
  * @returns {boolean} True when the note may be compiled here; `false` when
@@ -266,7 +273,7 @@ export class BasePackCompiler {
266
273
  eligibleFor(fm: object): boolean;
267
274
  /**
268
275
  * A refusal only this pass can make, because its subject is the note's
269
- * **type** (#330).
276
+ * **type**.
270
277
  *
271
278
  * The `assertNo*Field` family above it in the walk is type-agnostic by
272
279
  * construction: it runs before `selects`, so that a note declaring a
@@ -291,7 +298,7 @@ export class BasePackCompiler {
291
298
  * Whether this pass claims a note. **Required.**
292
299
  *
293
300
  * Called only for a note this build compiles — every note in the tree
294
- * belongs to the configured content package (#56) — so a subclass decides
301
+ * belongs to the configured content package — so a subclass decides
295
302
  * on `type` alone.
296
303
  *
297
304
  * @param {object} fm - The note's frontmatter.
@@ -368,8 +375,7 @@ export class BasePackCompiler {
368
375
  column?: number;
369
376
  }): void;
370
377
  /**
371
- * Report every `<system>.system` key the receiving subtype does not declare
372
- * (#58).
378
+ * Report every `<system>.system` key the receiving subtype does not declare.
373
379
  *
374
380
  * An **error**, not a warning: Foundry drops an unknown `system` key at
375
381
  * construction without a word, so the alternative is a document shipped
@@ -390,7 +396,7 @@ export class BasePackCompiler {
390
396
  reportUndeclaredSystemData(fm: object, block: string, documentType: string, subType: string): number;
391
397
  /**
392
398
  * Record every `system` key the *compiled document* carries that the
393
- * receiving subtype does not declare (#155).
399
+ * receiving subtype does not declare.
394
400
  *
395
401
  * The sibling of {@link BasePackCompiler#reportUndeclaredSystemData}, and
396
402
  * the half that sees what no declaration states. A compiler writes keys of
@@ -434,7 +440,7 @@ export class BasePackCompiler {
434
440
  /**
435
441
  * Emit the collected emitted-`system` findings, once each.
436
442
  *
437
- * An **error**, for the reason #60 made its sibling one: the value is gone
443
+ * An **error**, for the reason its sibling is one: the value is gone
438
444
  * at load and the build says nothing, and severity that varied by *which
439
445
  * part of the build wrote the key* would make the less fixable half the
440
446
  * quieter one. What varies is the message, which says whose fix it is —
@@ -529,7 +535,7 @@ export class BasePackCompiler {
529
535
  * note is one this build **refused** — it declares a retired frontmatter field
530
536
  * — and it is an error; a skipped one legitimately belongs to another pass, and
531
537
  * there are thousands of those. Folding the first into the second is what let a
532
- * whole tree be filtered out in silence (#56).
538
+ * whole tree be filtered out in silence.
533
539
  */
534
540
  export type PassStats = {
535
541
  /**
@@ -547,7 +553,7 @@ export type PassStats = {
547
553
  /**
548
554
  * - Notes this pack **refused** — one declaring a
549
555
  * retired frontmatter field, or one routed to a system pack whose system it
550
- * says nothing about (#58). Counted as errors, never as skips.
556
+ * says nothing about. Counted as errors, never as skips.
551
557
  */
552
558
  declined: number;
553
559
  };
@@ -35,7 +35,7 @@ export function bareAddress(value: unknown): string | null;
35
35
  * `### type: bundle` table puts it — the closed container, so a misspelled
36
36
  * `content` is a finding rather than a silently empty Adventure. It is accepted
37
37
  * at the top level too, exactly as a folder note's `parent` is: an author
38
- * following #259's own example rather than the specification should get a
38
+ * following the shipped example rather than the specification should get a
39
39
  * bundle, not a silent default.
40
40
  *
41
41
  * **Order is the author's**, and it is kept: an Adventure's `SetField` attaches
@@ -124,9 +124,9 @@ export function buildAdventure({ id, name, img, description, caption, folder, fl
124
124
  * world's collection already holds that `_id`, then creates or updates each.
125
125
  * Afterwards the documents live independently and the Adventure has no further
126
126
  * role. **It is an installer** — a set of document *copies* packaged for
127
- * one-shot import (#259).
127
+ * one-shot import.
128
128
  *
129
- * That is the whole difference from a folder (#256), which is a live grouping
129
+ * That is the whole difference from a folder, which is a live grouping
130
130
  * **by reference** that persists in the pack. A bundle carries copies and
131
131
  * exists to be imported once, so the two are not variations on one idea.
132
132
  *
@@ -8,7 +8,7 @@
8
8
  * the first.
9
9
  *
10
10
  * A **folder** document is skipped. It is emitted into every pack that holds
11
- * something filed in it (#257), so it is not one pack's document and has no
11
+ * something filed in it, so it is not one pack's document and has no
12
12
  * single note behind it; a bundle that wants folders is a question this pass
13
13
  * refuses rather than guesses at — see {@link Bundles#resolveAddress}.
14
14
  *
@@ -20,6 +20,15 @@
20
20
  * pack, which reordering cannot fix.
21
21
  */
22
22
  export function loadBundleSources(sourceDirs: Readonly<Record<string, readonly string[]>>): Map<string, object>;
23
+ /**
24
+ * Adventure pack compiler.
25
+ *
26
+ * Walks the content tree and compiles every `type: bundle` note into one
27
+ * Adventure per system, holding **copies** of the compiled documents its
28
+ * `contents` addresses name. Reading other passes' output is what
29
+ * {@link Bundles.readsPackOutputOf} declares, and what the generator orders the
30
+ * compile by.
31
+ */
23
32
  export class Bundles extends BasePackCompiler {
24
33
  /**
25
34
  * @param {object} options - As {@link BasePackCompiler}, plus:
@@ -94,12 +94,12 @@ export function matchAllOutsideCode(markdown: string, pattern: RegExp, options?:
94
94
  * **Which runs count as code is {@link codeRegions}' rule, not a second copy of
95
95
  * it.** The knowledgebase build carried its own regex once, and it was weaker in
96
96
  * two ways that both corrupted the one page whose subject *is* link syntax — so
97
- * its examples were exactly the input a looser rule mangles (SoHL#1665). A
97
+ * its examples are exactly the input a looser rule mangles. A
98
98
  * single-backtick span was allowed to cross newlines, so one odd backtick paired
99
99
  * with another paragraphs away and every span after it paired wrongly: prose was
100
100
  * masked as code while real spans were left exposed. And only three-backtick
101
101
  * fences were recognised, so a four-backtick example holding a three-backtick
102
- * block — the documented "fences of any length" case (#1505) — leaked its
102
+ * block — the documented "fences of any length" case — leaked its
103
103
  * contents.
104
104
  *
105
105
  * @param {string} body - The markdown body.
@@ -114,7 +114,7 @@ export function protectCode(body: string, transform: (masked: string) => string)
114
114
  * written. Every build-time rewriter that pattern-matches a body therefore has
115
115
  * to know where code is — otherwise a source listing that happens to contain
116
116
  * the rewriter's syntax is silently corrupted. Wikilink conversion met this as
117
- * `[[0]]` inside a fence being turned into a link (#1505), and it depended on
117
+ * `[[0]]` inside a fence being turned into a link, and it depended on
118
118
  * the surrounding literal's shape (`[[1,2],[3,4]]` survived), so the corruption
119
119
  * looked arbitrary.
120
120
  *
@@ -6,7 +6,7 @@
6
6
  * @param {object} opts
7
7
  * @param {object} [opts.config] The resolved build configuration, which
8
8
  * the two path arguments below default from. Supplying one is how a caller
9
- * compiles a package other than this repository's (#1508).
9
+ * compiles a package other than this repository's.
10
10
  * @param {string[]} [opts.sourcePacks] Every pack compiled from the content
11
11
  * tree, in compile order. Defaults to the configured pack directories.
12
12
  * @param {string} [opts.stageDest] Directory the LevelDB packs are built
@@ -15,10 +15,10 @@
15
15
  * @throws {Error} If pack JSON generation reported any error. Packs compiled
16
16
  * from incomplete or empty JSON ship blank or short compendiums, and the
17
17
  * omission is invisible until a player looks for content that is not there
18
- * (#1502) — so this is fatal, not a warning, and the caller is expected to
18
+ * — so this is fatal, not a warning, and the caller is expected to
19
19
  * turn it into a failing exit code.
20
20
  * @throws {Error} If a compiled pack ships a Scene that has lost its embedded
21
- * Level (#1538). Fatal for the same reason: Foundry reads a missing Level
21
+ * Level. Fatal for the same reason: Foundry reads a missing Level
22
22
  * record as "no levels" and persists that on the next world launch, so the
23
23
  * map image is gone before anyone notices it was ever at risk. See
24
24
  * {@link verifyPackSceneLevels}.
@@ -4,7 +4,7 @@
4
4
  * @param {object} opts - Options.
5
5
  * @param {string} opts.contentBase - Root of the content tree.
6
6
  * @param {readonly string[]} opts.skipDirectories - The scope, stated by the
7
- * caller as every corpus read requires (#243).
7
+ * caller as every corpus read requires.
8
8
  * @param {object} opts.router - The pack router this compile resolved. Shared
9
9
  * by every pass, which is what makes one link index correct for all of them.
10
10
  * @param {object} [opts.config] - The resolved configuration.