@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
@@ -24,7 +24,7 @@ export function declaredTags(type: string, groups?: object): readonly string[];
24
24
  */
25
25
  export function hasTag(fm: object | null | undefined, tag: string): boolean;
26
26
  /**
27
- * Whether a note is tagged as an unfinished **draft** (#183).
27
+ * Whether a note is tagged as an unfinished **draft**.
28
28
  *
29
29
  * The one reader of {@link DRAFT_TAG}, so both builds ask the same question of
30
30
  * the same field. Presentation only: a draft note is in the packs, in the
@@ -38,10 +38,11 @@ export function isDraftNote(fm: object | null | undefined): boolean;
38
38
  /**
39
39
  * What a note carrying a subType outside the address charset is told.
40
40
  *
41
- * **Why the charset holds for a subType, which reaches no address.** #206 said
41
+ * **Why the charset holds for a subType, which reaches no address.** The rule
42
+ * said
42
43
  * "the hyphen separates the segments of an address", and that was true of a
43
44
  * subType when it shipped: `sectionOf` returned a `doc`'s subType, so the value
44
- * was a URL path segment. #204 retired sections and it is not one now. The rule
45
+ * was a URL path segment. Sections are retired and it is not one. The rule
45
46
  * stays, on its own footing: a subType is a vocabulary term the whole toolchain
46
47
  * keys on, and it is one closed set away from being an address segment again —
47
48
  * so the reason to spell it in the address charset is that a charset holding
@@ -72,8 +73,8 @@ export function typeCharsetMessage(type: string): string;
72
73
  *
73
74
  * The message states the reason **per key**, as {@link typeCharsetMessage} and
74
75
  * {@link subTypeCharsetMessage} do: a type is an address segment, and a subType
75
- * has not been one since #204 retired sections, so a single claim covering both
76
- * would be half wrong (#210).
76
+ * is not one, since sections are retired, so a single claim covering both
77
+ * would be half wrong.
77
78
  *
78
79
  * @param {Readonly<Record<string, TypeVocabulary>>} vocabulary - The registry.
79
80
  * @param {string} [where] - What declares it, for the message.
@@ -104,19 +105,21 @@ export function dataFields(type: string, vocabulary?: Readonly<Record<string, Ty
104
105
  */
105
106
  export function subTypes(type: string, vocabulary?: Readonly<Record<string, TypeVocabulary>>): readonly string[] | null | undefined;
106
107
  /**
107
- * Every note type this toolchain compiles, and the closed vocabulary it
108
- * declares.
108
+ * The declared tag that marks a note as **unfinished**.
109
109
  *
110
- * Taken from the content-format specification, one `### type:` section per
111
- * entry. Where the specification and the shape notes are authored in today
112
- * disagree, the specification wins on the **name** that is what a `data:`
113
- * key will be called — and the disagreement is recorded on the field rather
114
- * than resolved silently.
110
+ * Named once and referenced from the declaration below, because a second
111
+ * spelling is how the two come apart: rename the tag in `DECLARED_TAGS` and a
112
+ * private copy elsewhere keeps matching the old word, silently.
115
113
  *
116
- * @type {Readonly<Record<string, TypeVocabulary>>}
114
+ * It is a **presentation** fact and nothing more. A draft note compiles,
115
+ * validates, publishes and resolves like any other; only a link *into* it
116
+ * renders marked. What it emphatically is not is the retired `draft:` field,
117
+ * whose entire effect was to move a note from published to unresolvable — see
118
+ * {@link draftRetiredMessage}.
117
119
  */
120
+ export const DRAFT_TAG: "draft";
118
121
  /**
119
- * The tags that **classify** a note, grouped by what they classify (#172).
122
+ * The tags that **classify** a note, grouped by what they classify.
120
123
  *
121
124
  * `tags:` lives at the open top level and most tags belong there: a theme, a
122
125
  * region, a working state is the author's own and this build has no opinion
@@ -141,20 +144,6 @@ export function subTypes(type: string, vocabulary?: Readonly<Record<string, Type
141
144
  * fishing village is a `village` that is `fishing`, and the single-valued field
142
145
  * this replaced had to spell it `Fishing Village` as a value of its own.
143
146
  */
144
- /**
145
- * The declared tag that marks a note as **unfinished** (#183).
146
- *
147
- * Named once and referenced from the declaration below, because a second
148
- * spelling is how the two come apart: rename the tag in `DECLARED_TAGS` and a
149
- * private copy elsewhere keeps matching the old word, silently.
150
- *
151
- * It is a **presentation** fact and nothing more. A draft note compiles,
152
- * validates, publishes and resolves like any other; only a link *into* it
153
- * renders marked. What it emphatically is not is the retired `draft:` field,
154
- * whose entire effect was to move a note from published to unresolvable — see
155
- * {@link draftRetiredMessage}.
156
- */
157
- export const DRAFT_TAG: "draft";
158
147
  export const DECLARED_TAGS: Readonly<{
159
148
  /** What a place *is*. */
160
149
  placeKind: Readonly<{
@@ -182,186 +171,25 @@ export const DECLARED_TAGS: Readonly<{
182
171
  tags: readonly string[];
183
172
  }>;
184
173
  }>;
185
- export const NOTE_VOCABULARY: Readonly<{
186
- being: Readonly<{
187
- subTypes: null;
188
- data: readonly DataFieldSpec[];
189
- }>;
190
- vehicle: Readonly<{
191
- subTypes: null;
192
- data: readonly DataFieldSpec[];
193
- }>;
194
- affiliation: Readonly<{
195
- subTypes: readonly string[];
196
- data: readonly DataFieldSpec[];
197
- }>;
198
- affliction: Readonly<{
199
- subTypes: readonly string[];
200
- data: readonly DataFieldSpec[];
201
- }>;
202
- armorgear: Readonly<{
203
- data: readonly DataFieldSpec[];
204
- }>;
205
- armorlocation: Readonly<{
206
- subTypes: null;
207
- data: readonly DataFieldSpec[];
208
- }>;
209
- attribute: Readonly<{
210
- data: readonly DataFieldSpec[];
211
- }>;
212
- concoctiongear: Readonly<{
213
- subTypes: readonly string[];
214
- data: readonly (DataFieldSpec | Readonly<{
215
- describe: "How many of the thing there are; one when unstated.";
216
- shape: "number";
217
- kind: "number";
218
- name: "quantity";
219
- }>)[];
220
- }>;
221
- containergear: Readonly<{
222
- data: readonly DataFieldSpec[];
223
- }>;
224
- miscgear: Readonly<{
225
- data: readonly (DataFieldSpec | Readonly<{
226
- describe: "How many of the thing there are; one when unstated.";
227
- shape: "number";
228
- kind: "number";
229
- name: "quantity";
230
- }>)[];
231
- }>;
232
- mystery: Readonly<{
233
- subTypes: readonly string[];
234
- data: readonly DataFieldSpec[];
235
- }>;
236
- mysticalability: Readonly<{
237
- subTypes: readonly string[];
238
- data: readonly DataFieldSpec[];
239
- }>;
240
- projectilegear: Readonly<{
241
- subTypes: readonly string[];
242
- data: readonly (DataFieldSpec | Readonly<{
243
- describe: "How many of the thing there are; one when unstated.";
244
- shape: "number";
245
- kind: "number";
246
- name: "quantity";
247
- }>)[];
248
- }>;
249
- skill: Readonly<{
250
- subTypes: readonly string[];
251
- data: readonly DataFieldSpec[];
252
- }>;
253
- trauma: Readonly<{
254
- subTypes: readonly string[];
255
- data: readonly DataFieldSpec[];
256
- }>;
257
- weapongear: Readonly<{
258
- data: readonly DataFieldSpec[];
259
- }>;
260
- doc: Readonly<{
261
- subTypes: readonly string[];
262
- data: readonly never[];
263
- }>;
264
- macro: Readonly<{
265
- data: readonly never[];
266
- }>;
267
- folder: Readonly<{
268
- data: readonly ({
269
- describe: string;
270
- shape: "a wikilink, or a map of wikilinks keyed by pack";
271
- kind: "scalar-or-map";
272
- entryShape: "a wikilink";
273
- keys: "pack";
274
- name: string;
275
- } | {
276
- describe: string;
277
- shape: "string";
278
- kind: "string";
279
- name: string;
280
- })[];
281
- }>;
282
- bundle: Readonly<{
283
- data: readonly {
284
- describe: string;
285
- shape: "list of wikilinks";
286
- kind: "list";
287
- name: string;
288
- }[];
289
- }>;
290
- lore: Readonly<{
291
- subTypes: readonly string[];
292
- data: readonly never[];
293
- }>;
294
- place: Readonly<{
295
- subTypes: readonly string[];
296
- data: readonly ({
297
- describe: string;
298
- shape: "string";
299
- kind: "string";
300
- name: string;
301
- } | {
302
- describe: string;
303
- shape: "list of wikilinks";
304
- kind: "list";
305
- name: string;
306
- } | {
307
- describe: string;
308
- shape: "number";
309
- kind: "number";
310
- name: string;
311
- })[];
312
- }>;
313
- scenario: Readonly<{
314
- subTypes: readonly string[];
315
- data: readonly ({
316
- describe: string;
317
- shape: "list of wikilinks";
318
- kind: "list";
319
- name: string;
320
- } | {
321
- describe: string;
322
- shape: "string";
323
- kind: "string";
324
- name: string;
325
- } | {
326
- describe: string;
327
- shape: "list";
328
- kind: "list";
329
- name: string;
330
- })[];
331
- }>;
332
- homepage: Readonly<{
333
- data: readonly never[];
334
- }>;
335
- map: Readonly<{
336
- subTypes: readonly string[];
337
- data: readonly ({
338
- describe: string;
339
- shape: "string";
340
- kind: "string";
341
- name: string;
342
- } | {
343
- describe: string;
344
- shape: "list";
345
- kind: "list";
346
- name: string;
347
- } | {
348
- describe: string;
349
- shape: "number";
350
- kind: "number";
351
- name: string;
352
- } | {
353
- describe: string;
354
- shape: "as authored";
355
- name: string;
356
- })[];
357
- }>;
358
- }>;
174
+ /**
175
+ * Every note type this toolchain compiles, and the closed vocabulary it
176
+ * declares.
177
+ *
178
+ * Taken from the content-format specification, one `### type:` section per
179
+ * entry. Where the specification and the shape notes are authored in today
180
+ * disagree, the specification wins on the **name** — that is what a `data:`
181
+ * key will be called — and the disagreement is recorded on the field rather
182
+ * than resolved silently.
183
+ *
184
+ * @type {Readonly<Record<string, TypeVocabulary>>}
185
+ */
186
+ export const NOTE_VOCABULARY: Readonly<Record<string, TypeVocabulary>>;
359
187
  /**
360
188
  * One `data:` key a note type may carry.
361
189
  *
362
190
  * A deliberate subset of {@link import ("./field-spec.mjs").FieldSpec}: no `to`,
363
191
  * because nothing here builds anything yet. Reading `data.*` through into a
364
- * document's `system` block is the passthrough slice (#126), and claiming an
192
+ * document's `system` block is the passthrough slice, and claiming an
365
193
  * emitted path this does not produce would be a lie in the one place a reader
366
194
  * would trust it.
367
195
  */
@@ -20,7 +20,7 @@ export function findConfigFile(from: string): string | undefined;
20
20
  *
21
21
  * Kept separate from {@link loadPackConfig} because the *choice* is worth being
22
22
  * able to ask about without loading anything: the two walks disagreeing is the
23
- * observable form of #364, and a caller that wants to report it — or a test
23
+ * observable form of that, and a caller that wants to report it — or a test
24
24
  * that wants to describe it — should not have to reproduce the resolution and
25
25
  * risk disagreeing with the loader about it. It performs I/O, and is named for
26
26
  * it, like the {@link findConfigFile} it calls twice.
@@ -58,7 +58,7 @@ export function resolveConfigFile({ cwd, moduleDir }?: {
58
58
  * worse than locating none — a reader would learn that some configuration
59
59
  * errors carry a position and could not predict which — so the path rides on
60
60
  * the error and every one of them is located here, at the boundary that knows
61
- * which file was read (#95).
61
+ * which file was read.
62
62
  *
63
63
  * The message keeps its body and gains the `file:line:column: error: ` prefix
64
64
  * every other finding in this build already uses, so nothing a reader has today
@@ -82,7 +82,7 @@ export function locateConfigError(err: unknown, configPath?: string): unknown;
82
82
  * cannot write `import.meta.dirname`, and any absolute path it wrote instead
83
83
  * would be one machine's — so authoring it is rejected rather than honoured.
84
84
  * - **`itemBuilders`** is a *name* (`sohl`) — or a list of names, for a tree
85
- * feeding more than one system (#58) — resolved against the built-in
85
+ * feeding more than one system — resolved against the built-in
86
86
  * registries. A registry's name is the system it belongs to. A registry of a
87
87
  * consumer's own is code, and code goes in an `.mjs` configuration.
88
88
  * - **`stats.systemVersion`** is derived from the adjacent `package.json` when
@@ -95,11 +95,11 @@ export function locateConfigError(err: unknown, configPath?: string): unknown;
95
95
  *
96
96
  * @param {unknown} data - The parsed configuration document.
97
97
  * @param {string} configPath - Absolute path of the file it was parsed from.
98
- * @returns {import("../config.mjs").ContentBuildConfig} The frozen configuration.
98
+ * @returns {import("../content-config.mjs").ContentBuildConfig} The frozen configuration.
99
99
  * @throws {Error} When the document is not a mapping, declares `rootDir`, or
100
100
  * names an item-builder registry this package does not ship.
101
101
  */
102
- export function configFromData(data: unknown, configPath: string): import("../config.mjs").ContentBuildConfig;
102
+ export function configFromData(data: unknown, configPath: string): import("../content-config.mjs").ContentBuildConfig;
103
103
  /**
104
104
  * The consuming repository's resolved, frozen configuration.
105
105
  *
@@ -108,12 +108,12 @@ export function configFromData(data: unknown, configPath: string): import("../co
108
108
  * configuration (#2). The result is memoised, so calling it in a default
109
109
  * parameter — the usual spelling here — costs one property read per call.
110
110
  *
111
- * @returns {import("../config.mjs").ContentBuildConfig} The frozen configuration.
111
+ * @returns {import("../content-config.mjs").ContentBuildConfig} The frozen configuration.
112
112
  * @throws {Error} When no configuration file can be found, or the one named
113
113
  * cannot be loaded. Absence is a defect, not a fallback: without it the
114
114
  * compilers know neither what to compile nor where to put it.
115
115
  */
116
- export function loadPackConfig(): import("../config.mjs").ContentBuildConfig;
116
+ export function loadPackConfig(): import("../content-config.mjs").ContentBuildConfig;
117
117
  /**
118
118
  * The file {@link loadPackConfig} resolved the configuration from.
119
119
  *
@@ -48,7 +48,7 @@ export class PackRoutingError extends Error {
48
48
  *
49
49
  * Deliberately close to the retired `package:` and deliberately not the same
50
50
  * word: `package:` said which *distribution* owned a note — now the
51
- * repository's `contentPackage`, and no longer authorable (#56) — while `pack:`
51
+ * repository's `contentPackage`, and no longer authorable — while `pack:`
52
52
  * says which *compendium* receives its document.
53
53
  */
54
54
  export const PACK_FIELD: "pack";
@@ -0,0 +1,42 @@
1
+ /**
2
+ * The file name a downloaded book identifies itself by.
3
+ *
4
+ * The zip and the manifest take their names from the manifest, so an asset's
5
+ * name and its advertised URL cannot disagree. A PDF has no advertised URL, so
6
+ * its name is a free choice — which is exactly why it is fixed here rather than
7
+ * left for each of six consumers to invent.
8
+ *
9
+ * @param {string} artifact - The package's artifact name.
10
+ * @param {string} version - The version being released.
11
+ * @returns {string} `<artifact>-<version>.pdf`, or `<artifact>.pdf` unversioned.
12
+ */
13
+ export function pdfFileName(artifact: string, version: string): string;
14
+ /**
15
+ * Build the book.
16
+ *
17
+ * @param {object} [opts] - Options.
18
+ * @param {object} [opts.config] - A resolved configuration; loaded when absent.
19
+ * @param {string} [opts.out] - Where to write, overriding `pdf.out`.
20
+ * @param {string} [opts.version] - Stamped on the title page and the file name.
21
+ * @param {boolean} [opts.compile] - Whether to run Typst. False leaves the
22
+ * `.typ` source, which is what the unit tests read.
23
+ * @returns {Promise<object>} `{ built, reason, findings, typ, pdf, stats }`.
24
+ */
25
+ export function buildPdf({ config, out, version, compile }?: {
26
+ config?: object | undefined;
27
+ out?: string | undefined;
28
+ version?: string | undefined;
29
+ compile?: boolean | undefined;
30
+ }): Promise<object>;
31
+ /**
32
+ * Run Typst over the emitted source.
33
+ *
34
+ * @param {string} typPath - The `.typ` file.
35
+ * @param {string} pdfPath - Where the PDF goes.
36
+ * @param {object} pdf - The resolved `pdf:` block.
37
+ * @returns {{ok: boolean, message: string}} What happened.
38
+ */
39
+ export function compileTypst(typPath: string, pdfPath: string, pdf?: object): {
40
+ ok: boolean;
41
+ message: string;
42
+ };
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Every glyph name a font carries, with the codepoint that reaches it.
3
+ *
4
+ * @param {string} file - Path to a `.ttf`/`.otf`.
5
+ * @returns {Map<string, number>} Name → codepoint.
6
+ */
7
+ export function glyphTable(file: string): Map<string, number>;
8
+ /**
9
+ * The family name a font file announces, for Typst's `text(font: …)`.
10
+ *
11
+ * Read from the `name` table rather than from the file name, because the file
12
+ * is what a consumer happened to call it and the family is what the font stack
13
+ * will match on.
14
+ *
15
+ * @param {string} file - Path to a `.ttf`/`.otf`.
16
+ * @returns {string} The family name, or "" when the table cannot be read.
17
+ */
18
+ export function familyName(file: string): string;
19
+ /**
20
+ * Resolve every icon in a registry against the fonts a consumer named.
21
+ *
22
+ * @param {object} registry - The resolved `icons:` registry.
23
+ * @param {Record<string, string>} iconFonts - Family name → font file.
24
+ * @param {object[]} [findings] - Collected here rather than thrown.
25
+ * @returns {Map<string, {font: string, codepoint: number}>} Icon name → glyph.
26
+ */
27
+ export function resolveIconGlyphs(registry: object, iconFonts?: Record<string, string>, findings?: object[]): Map<string, {
28
+ font: string;
29
+ codepoint: number;
30
+ }>;
@@ -0,0 +1,144 @@
1
+ /**
2
+ * Escape literal text for Typst markup.
3
+ *
4
+ * @param {string} text - Text as the author wrote it.
5
+ * @returns {string} The same text, inert.
6
+ */
7
+ export function escapeTypst(text: string): string;
8
+ /**
9
+ * Escape a string going inside Typst string quotes, as a `#link` URL does.
10
+ *
11
+ * @param {string} text - The raw value.
12
+ * @returns {string} The same value, quotable.
13
+ */
14
+ export function escapeTypstString(text: string): string;
15
+ /**
16
+ * A Typst label, from a plan anchor.
17
+ *
18
+ * Typst labels admit a narrower charset than an anchor does, so anything else
19
+ * folds to a hyphen. The plan already guarantees anchors are unique, and a fold
20
+ * that merged two of them would silently give one destination two meanings —
21
+ * so the fold is injective by construction: only characters Typst rejects move,
22
+ * and they move to a character the slugifier never emits twice in a row.
23
+ *
24
+ * @param {string} anchor - The plan's anchor.
25
+ * @returns {string} A Typst label name.
26
+ */
27
+ export function labelFor(anchor: string): string;
28
+ /**
29
+ * A markdown-it configured to parse, not to render.
30
+ *
31
+ * `html: false` is the load-bearing setting: raw HTML in a note has no route to
32
+ * Typst at all, which is why {@link module:engine/content-html} reports it. With
33
+ * HTML disabled markdown-it emits the tag as text, so it arrives in the book
34
+ * visibly wrong rather than invisibly missing.
35
+ *
36
+ * @param {object} [registry] - The icon registry.
37
+ * @returns {object} A markdown-it instance.
38
+ */
39
+ export function createParser(registry?: object): object;
40
+ /**
41
+ * Render markdown as Typst content.
42
+ *
43
+ * @param {string} markdown - The note's body, tables expanded and links resolved.
44
+ * @param {object} [opts] - Options.
45
+ * @param {object} [opts.md] - A parser from {@link createParser}, reused across
46
+ * a whole book rather than rebuilt for each of 2,500 notes.
47
+ * @param {object} [opts.registry] - The icon registry, when no parser is passed.
48
+ * @param {Map<string, string>} [opts.links] - Address slug → plan anchor.
49
+ * @param {Map<string, string>} [opts.glyphs] - Icon name → `{font, char}`.
50
+ * @param {number} [opts.headingOffset] - Added to every heading level, so a
51
+ * note's own `##` nests beneath the entry heading the book gave it.
52
+ * @param {string} [opts.anchorPrefix] - The entry's anchor, which namespaces
53
+ * every `{#slug}` the body declares.
54
+ * @returns {string} Typst markup.
55
+ */
56
+ export function markdownToTypst(markdown: string, opts?: {
57
+ md?: object | undefined;
58
+ registry?: object | undefined;
59
+ links?: Map<string, string> | undefined;
60
+ glyphs?: Map<string, string> | undefined;
61
+ headingOffset?: number | undefined;
62
+ anchorPrefix?: string | undefined;
63
+ }): string;
64
+ /**
65
+ * The whole book, as one Typst document.
66
+ *
67
+ * **Pure, and that is the point.** Everything a reviewer of #316 has to check
68
+ * about structure — the outline's shape, the anchors, which links went inward,
69
+ * the order entries print in — is decided here from a plan and a map of bodies,
70
+ * with no filesystem and no compiler. {@link module:engine/pdf-build} supplies
71
+ * both and runs Typst over the result.
72
+ *
73
+ * ## Two outlines, and why they are not the same outline
74
+ *
75
+ * A roster of 2,500 entries wants every entry reachable from a viewer's
76
+ * sidebar, and emphatically does not want all 2,500 printed in the front
77
+ * matter: that is forty pages of contents before the book starts.
78
+ *
79
+ * Typst separates the two for us. **The PDF bookmark outline is built from
80
+ * every heading**, so each entry gets its own node at its own depth for free
81
+ * and the sidebar is the navigational interface the issue asks for.
82
+ * **`#outline()` prints only to `tocDepth`**, so the paper table of contents
83
+ * stays the sections. Both are page-numbered and both are links.
84
+ *
85
+ * ## Headings carry the structure, so nothing else has to
86
+ *
87
+ * Every section, every prose file and every entry is a real Typst heading at
88
+ * its plan depth. That single decision supplies the bookmarks, the printed
89
+ * contents, the running heads and the page breaks at once — where drawing
90
+ * titles as styled text would have meant building all four by hand and keeping
91
+ * them agreeing with each other.
92
+ *
93
+ * @param {object} opts - Options.
94
+ * @param {object} opts.plan - From {@link module:engine/pdf-toc.planDocument}.
95
+ * @param {Map<string, string>} opts.bodies - Anchor → the entry's rendered
96
+ * Typst body. An entry with no body prints its heading alone.
97
+ * @param {string} opts.title - The document's title.
98
+ * @param {string} [opts.subtitle] - Shown under it on the title page.
99
+ * @param {string[]} [opts.front] - Rendered Typst for each front-matter file.
100
+ * @param {object} [opts.fonts] - `{ serif, sans, mono }` family names.
101
+ * @param {number} [opts.tocDepth] - How deep the *printed* contents go.
102
+ * @param {string} [opts.version] - Stamped on the title page when given.
103
+ * @returns {string} A complete `.typ` document.
104
+ */
105
+ export function renderBook({ plan, bodies, title, subtitle, front, fonts, tocDepth, version, }?: {
106
+ plan: object;
107
+ bodies: Map<string, string>;
108
+ title: string;
109
+ subtitle?: string | undefined;
110
+ front?: string[] | undefined;
111
+ fonts?: object | undefined;
112
+ tocDepth?: number | undefined;
113
+ version?: string | undefined;
114
+ }): string;
115
+ /**
116
+ * Point every internal link at a label the document actually declares.
117
+ *
118
+ * **Typst refuses to compile a reference to a label that is not there.** That
119
+ * makes one mistyped `[[note#appearance]]`, or an anchor written inside a code
120
+ * fence where no heading is emitted, fatal to a 1,200-page book — and fatal at
121
+ * the very end, after everything else has succeeded. A reference book cannot
122
+ * have that failure mode: the link is the least important thing on the page and
123
+ * would be taking the other two thousand entries down with it.
124
+ *
125
+ * So references are reconciled against declarations before the source is
126
+ * written. A link to a section that does not exist falls back to the **entry**
127
+ * that would have contained it, which is where a reader wants to end up anyway;
128
+ * a link with no entry to fall back to becomes plain text. Both are reported.
129
+ *
130
+ * A declaration is a label not preceded by `#link(` — the only two places a
131
+ * label appears are the heading that declares one and the link that uses one.
132
+ *
133
+ * @param {string} source - The assembled Typst document.
134
+ * @param {object[]} [findings] - Collected here rather than thrown.
135
+ * @returns {string} The same document, with no reference left dangling.
136
+ */
137
+ export function resolveDanglingLabels(source: string, findings?: object[]): string;
138
+ /**
139
+ * Every icon name a body uses, so a build can resolve them once.
140
+ *
141
+ * @param {string} markdown - A note body.
142
+ * @returns {string[]} The names, in order of appearance, with repeats.
143
+ */
144
+ export function iconNamesIn(markdown: string): string[];