@heroiclands/package-build 23.0.0 → 23.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (157) hide show
  1. package/CHANGELOG.md +66 -0
  2. package/README.md +1 -1
  3. package/bin/content-commands.mjs +1 -1
  4. package/ci/content-format-reference.mjs +46 -0
  5. package/docs/api.md +124 -141
  6. package/docs/authoring/assets.md +1 -1
  7. package/docs/authoring/dates-and-calendars.md +12 -6
  8. package/docs/authoring/frontmatter.md +2 -2
  9. package/docs/authoring/links-and-markup.md +145 -29
  10. package/docs/commands.md +8 -10
  11. package/docs/configuration.md +13 -11
  12. package/docs/content-format.md +2 -2
  13. package/docs/guides/book.md +59 -4
  14. package/docs/guides/icons.md +4 -5
  15. package/docs/guides/packs.md +6 -0
  16. package/docs/guides/reference-pages.md +21 -1
  17. package/docs/guides/release-and-deploy.md +39 -7
  18. package/docs/guides/site.md +17 -18
  19. package/docs/reference/format-details.md +877 -276
  20. package/docs/reference/note-types.md +278 -91
  21. package/docs/reference/theme-pages.md +58 -97
  22. package/engine/address-values.mjs +124 -4
  23. package/engine/address.mjs +44 -3
  24. package/engine/anchors.mjs +103 -3
  25. package/engine/art-slots.mjs +2 -9
  26. package/engine/base-compiler.mjs +25 -6
  27. package/engine/calendar-artifacts.mjs +4 -1
  28. package/engine/calendar-notes.mjs +166 -102
  29. package/engine/content-format-check.mjs +2 -3
  30. package/engine/content-format.mjs +44 -1
  31. package/engine/content-format.yaml +79 -16
  32. package/engine/content-images.mjs +10 -1
  33. package/engine/content-index.mjs +37 -9
  34. package/engine/content-links.mjs +24 -5
  35. package/engine/content-tables.mjs +24 -3
  36. package/engine/data-keys.mjs +347 -0
  37. package/engine/derived-sections.mjs +322 -0
  38. package/engine/diagnostics.mjs +28 -0
  39. package/engine/event-fields.mjs +187 -0
  40. package/engine/event-rows.mjs +126 -0
  41. package/engine/event-views.mjs +305 -0
  42. package/engine/exported-scene.mjs +29 -53
  43. package/engine/frontmatter-lint.mjs +103 -77
  44. package/engine/frontmatter.mjs +7 -2
  45. package/engine/generate.mjs +53 -0
  46. package/engine/generated-sections.mjs +223 -0
  47. package/engine/heading-attributes.mjs +4 -2
  48. package/engine/helpers.mjs +12 -1
  49. package/engine/holdings.mjs +12 -33
  50. package/engine/ids.mjs +17 -11
  51. package/engine/index.mjs +4 -4
  52. package/engine/infobox-render.mjs +21 -6
  53. package/engine/infobox.mjs +217 -99
  54. package/engine/journals.mjs +104 -47
  55. package/engine/literature-notes.mjs +4 -1
  56. package/engine/literature-works.mjs +21 -13
  57. package/engine/map-graphviz.mjs +4 -18
  58. package/engine/markdown-expressions.mjs +116 -11
  59. package/engine/metadata-index.mjs +26 -0
  60. package/engine/near-miss.mjs +90 -0
  61. package/engine/note-addresses.mjs +75 -19
  62. package/engine/note-dates.mjs +5 -3
  63. package/engine/note-event-terms.mjs +364 -0
  64. package/engine/note-events.mjs +823 -0
  65. package/engine/note-vocabulary.mjs +184 -88
  66. package/engine/office-holders.mjs +20 -54
  67. package/engine/packagebuild-index.mjs +16 -1
  68. package/engine/pdf-build.mjs +97 -60
  69. package/engine/pdf-index.mjs +263 -0
  70. package/engine/pdf-render.mjs +47 -5
  71. package/engine/place-relation-terms.mjs +174 -0
  72. package/engine/place-relations.mjs +72 -160
  73. package/engine/rank-ladder.mjs +14 -41
  74. package/engine/reckoning-markers.mjs +2 -0
  75. package/engine/region-events.mjs +6 -12
  76. package/engine/scenes.mjs +73 -468
  77. package/engine/site-build.mjs +75 -101
  78. package/engine/site-index.mjs +3 -1
  79. package/engine/site-maps.mjs +43 -29
  80. package/engine/site-preview.mjs +40 -31
  81. package/engine/social-ties.mjs +2 -1
  82. package/engine/sql-tables.mjs +212 -9
  83. package/engine/standing-terms.mjs +145 -6
  84. package/engine/standings.mjs +37 -49
  85. package/engine/web-wikilinks.mjs +21 -1
  86. package/engine/wikilink-syntax.mjs +34 -4
  87. package/engine/wikilinks.mjs +27 -2
  88. package/engine/yaml-lint.mjs +7 -4
  89. package/hugo-theme/layouts/partials/infobox/entry.html +4 -1
  90. package/hugo-theme/layouts/partials/page-body.html +0 -3
  91. package/hugo-theme/static/css/style.css +25 -55
  92. package/package.json +1 -2
  93. package/packagebuild-metadata.jsonl +13 -13
  94. package/release.mjs +62 -4
  95. package/sohl/note-schemas.mjs +8 -73
  96. package/types/engine/address-values.d.mts +50 -3
  97. package/types/engine/address.d.mts +21 -0
  98. package/types/engine/anchors.d.mts +49 -2
  99. package/types/engine/art-slots.d.mts +1 -1
  100. package/types/engine/base-compiler.d.mts +13 -4
  101. package/types/engine/calendar-notes.d.mts +7 -0
  102. package/types/engine/content-format.d.mts +52 -0
  103. package/types/engine/content-images.d.mts +5 -1
  104. package/types/engine/content-tables.d.mts +9 -1
  105. package/types/engine/data-keys.d.mts +145 -0
  106. package/types/engine/derived-sections.d.mts +73 -0
  107. package/types/engine/diagnostics.d.mts +15 -0
  108. package/types/engine/event-fields.d.mts +99 -0
  109. package/types/engine/event-rows.d.mts +12 -0
  110. package/types/engine/event-views.d.mts +67 -0
  111. package/types/engine/exported-scene.d.mts +5 -2
  112. package/types/engine/frontmatter-lint.d.mts +3 -3
  113. package/types/engine/generated-sections.d.mts +143 -0
  114. package/types/engine/holdings.d.mts +6 -20
  115. package/types/engine/ids.d.mts +15 -12
  116. package/types/engine/index.d.mts +1 -1
  117. package/types/engine/infobox.d.mts +13 -3
  118. package/types/engine/journals.d.mts +24 -11
  119. package/types/engine/literature-works.d.mts +1 -2
  120. package/types/engine/map-graphviz.d.mts +2 -10
  121. package/types/engine/markdown-expressions.d.mts +12 -3
  122. package/types/engine/near-miss.d.mts +42 -0
  123. package/types/engine/note-addresses.d.mts +7 -1
  124. package/types/engine/note-event-terms.d.mts +68 -0
  125. package/types/engine/note-events.d.mts +71 -0
  126. package/types/engine/note-vocabulary.d.mts +37 -8
  127. package/types/engine/office-holders.d.mts +3 -0
  128. package/types/engine/pdf-index.d.mts +35 -0
  129. package/types/engine/pdf-render.d.mts +8 -2
  130. package/types/engine/place-relation-terms.d.mts +83 -0
  131. package/types/engine/place-relations.d.mts +11 -66
  132. package/types/engine/rank-ladder.d.mts +2 -0
  133. package/types/engine/region-events.d.mts +6 -12
  134. package/types/engine/scenes.d.mts +6 -32
  135. package/types/engine/site-build.d.mts +8 -22
  136. package/types/engine/site-maps.d.mts +15 -7
  137. package/types/engine/sql-tables.d.mts +77 -2
  138. package/types/engine/standing-terms.d.mts +37 -4
  139. package/types/engine/standings.d.mts +14 -9
  140. package/types/engine/wikilink-syntax.d.mts +20 -0
  141. package/types/engine/wikilinks.d.mts +3 -2
  142. package/types/engine/yaml-lint.d.mts +5 -4
  143. package/types/release.d.mts +4 -0
  144. package/docs/guides/government-migration.md +0 -52
  145. package/engine/itinerary-scenes.mjs +0 -166
  146. package/engine/lore-events.mjs +0 -197
  147. package/engine/map-notes.mjs +0 -1309
  148. package/engine/map-raster.mjs +0 -51
  149. package/hugo-theme/layouts/partials/holdings/entry.html +0 -21
  150. package/hugo-theme/layouts/partials/holdings/kind-groups.html +0 -71
  151. package/hugo-theme/layouts/partials/holdings.html +0 -61
  152. package/hugo-theme/layouts/partials/literature-works.html +0 -29
  153. package/hugo-theme/layouts/partials/place-map.html +0 -9
  154. package/types/engine/itinerary-scenes.d.mts +0 -29
  155. package/types/engine/lore-events.d.mts +0 -14
  156. package/types/engine/map-notes.d.mts +0 -297
  157. package/types/engine/map-raster.d.mts +0 -8
@@ -106,6 +106,27 @@ export function parseAddress(written: unknown, defaults?: AddressDefaults, { dec
106
106
  declared?: boolean;
107
107
  legacyShortcodeCase?: boolean;
108
108
  }): AddressTuple | AddressProblem;
109
+ /**
110
+ * Split a written value at its anchor.
111
+ *
112
+ * The anchor is everything after the first `#`, and the Address everything
113
+ * before it; both are trimmed. A value with no `#` has no `anchor` key at
114
+ * all, which is how a caller tells "no anchor" from `place-x#`, an empty one.
115
+ *
116
+ * @param {string} written - The value as authored, any Wikilink label removed.
117
+ * @returns {{address: string, anchor?: string}} The two parts.
118
+ */
119
+ export function splitAnchor(written: string): {
120
+ address: string;
121
+ anchor?: string;
122
+ };
123
+ /**
124
+ * Whether a written value carries an anchor.
125
+ *
126
+ * @param {unknown} written - The value as authored.
127
+ * @returns {boolean} Whether it is a string holding a `#`.
128
+ */
129
+ export function hasAnchor(written: unknown): boolean;
109
130
  /**
110
131
  * Whether a value is an internally parsed Address.
111
132
  * @param {unknown} value - A property value.
@@ -12,14 +12,15 @@
12
12
  * picture's address to the role its asset declares, so a figure anchor's
13
13
  * `name` reads `Map 1` rather than `Figure 1` where it is due — see
14
14
  * {@link module:engine/content-figures.scanFigures}.
15
- * @returns {Array<{slug: string, name: string, level: number, line: number}>}
16
- * In document order.
15
+ * @returns {Array<{slug: string, name: string, level: number, line: number,
16
+ * kind: string}>} In document order.
17
17
  */
18
18
  export function collectAnchors(body: string, bodyLine?: number, resolveRole?: (address: string) => string | undefined): Array<{
19
19
  slug: string;
20
20
  name: string;
21
21
  level: number;
22
22
  line: number;
23
+ kind: string;
23
24
  }>;
24
25
  /** Collisions involving a div, verse or inline-span anchor.
25
26
  * Heading and caption collisions are diagnosed by their existing scanners.
@@ -31,3 +32,49 @@ export function markupAnchorFindings(body: string): Array<{
31
32
  column: number;
32
33
  message: string;
33
34
  }>;
35
+ /**
36
+ * The anchors a note's events declare: one per `data.events` entry carrying
37
+ * an `id`, at the line its `id` is written on.
38
+ *
39
+ * The `id` is taken as written — {@link module:engine/note-events} holds it to
40
+ * the address-segment charset — and named by the note's own name for the event
41
+ * when one is given, else by its summary.
42
+ *
43
+ * @param {object} fm - The note's frontmatter.
44
+ * @param {string} [raw] - The note's full text, for the line; without it the
45
+ * line is omitted rather than guessed.
46
+ * @returns {Array<{slug: string, name: string, level: number, line?: number,
47
+ * kind: "event"}>} In entry order.
48
+ */
49
+ export function eventAnchors(fm: object, raw?: string): Array<{
50
+ slug: string;
51
+ name: string;
52
+ level: number;
53
+ line?: number;
54
+ kind: "event";
55
+ }>;
56
+ /**
57
+ * Event `id`s that repeat one of the note's body anchors.
58
+ *
59
+ * A note's anchors are one namespace, so `place-ironfells#sack` names one
60
+ * thing whether `sack` is a heading or an event. Two body anchors that collide
61
+ * are reported by the scanners that read them, and two events sharing an `id`
62
+ * by the event check; this reports the remaining case, an event against a body
63
+ * anchor, at the event's `id`.
64
+ *
65
+ * @param {{file: string, fm: object, raw?: string, body?: string}} note - The
66
+ * note, as the link index hands it over.
67
+ * @returns {object[]} Findings, each at the colliding `id`.
68
+ */
69
+ export function noteAnchorFindings(note: {
70
+ file: string;
71
+ fm: object;
72
+ raw?: string;
73
+ body?: string;
74
+ }): object[];
75
+ /**
76
+ * What an anchor marks. `prose` is every anchor the body declares — a heading,
77
+ * a caption, a block, an alert, a poem or a span — and `event` is the `id` of
78
+ * an entry in `data.events`.
79
+ */
80
+ export const ANCHOR_KINDS: readonly string[];
@@ -1,5 +1,5 @@
1
1
  /**
2
- * The four art slots, in the order the specification tabulates them.
2
+ * The art slots, in the order the specification tabulates them.
3
3
  *
4
4
  * `banner` is the one that reaches no compiled document: it is the page's hero
5
5
  * image, read by the site and by nothing else. The book's section plates read a
@@ -104,10 +104,8 @@ export class BasePackCompiler {
104
104
  * here is what lets the lint tell an inert key from a live one.
105
105
  *
106
106
  * A pass that emits art **anywhere** in its document declares it, not only
107
- * one that writes a top-level `img`: the scenes pass puts the path on the
108
- * scene's background rather than on a property called `img`, and the value
109
- * is no less live for it. The question this answers is whether the authored
110
- * path reaches the output at all.
107
+ * one that writes a top-level `img`. The question this answers is whether
108
+ * the authored path reaches the output at all.
111
109
  *
112
110
  * @type {readonly string[]}
113
111
  */
@@ -392,6 +390,17 @@ export class BasePackCompiler {
392
390
  * that does not convert.
393
391
  */
394
392
  convertBody(fm: object, body: string): string;
393
+ /**
394
+ * Every note's events by Address, for an inline reference to an event's
395
+ * field — built once per compile from the corpus's records and the fetched
396
+ * dependency indexes, the same inputs the website and the book build it
397
+ * from, so a reference prints the same text on all three.
398
+ *
399
+ * @returns {{note: (written: string) => object|undefined}} The lookup.
400
+ */
401
+ eventNotes(): {
402
+ note: (written: string) => object | undefined;
403
+ };
395
404
  /**
396
405
  * The Foundry path one authored art address names, or `null`.
397
406
  *
@@ -163,6 +163,13 @@ export const INVARIANT_SUBTYPES: readonly string[];
163
163
  /** Calendaria's display locations that a calendar note can format. */
164
164
  export const CALENDAR_DATE_FORMAT_KEYS: readonly string[];
165
165
  export { CALENDAR_FORMAT_TOKENS };
166
+ /**
167
+ * The keys of one entry in each of a calendar's lists, as inner-key
168
+ * declarations.
169
+ *
170
+ * @type {Readonly<Record<string, readonly import("./data-keys.mjs").InnerKeySpec[]>>}
171
+ */
172
+ export const CALENDAR_ENTRY_FIELDS: Readonly<Record<string, readonly import("./data-keys.mjs").InnerKeySpec[]>>;
166
173
  /**
167
174
  * The `data:` keys a calendar note may write — the closed list, in authored
168
175
  * order.
@@ -53,10 +53,21 @@ export const CONTENT_FORMAT_PATH: string;
53
53
  * property — what a note actually writes. `appearance.eye_color` is authored
54
54
  * as `appearance`, so that is the key recorded.
55
55
  * @property {Set<string>} dataPaths - The declared paths, whole.
56
+ * @property {Map<string, DataRow>} [dataRows] - Each documented path's row, as
57
+ * a reference document states it. Read from a Markdown specification only.
56
58
  * @property {string[]} subTypes - The declared `subType` values,
57
59
  * in document order — empty when it states none, which is the ordinary case
58
60
  * for a type that has no `subType` at all.
59
61
  */
62
+ /**
63
+ * One row of a `data` property table, as a reference document states it.
64
+ *
65
+ * @typedef {object} DataRow
66
+ * @property {string} shape - The second cell, the value's shape in words.
67
+ * @property {string} text - The whole row as written, for a reader looking for
68
+ * a marker anywhere in it.
69
+ * @property {number} line - 1-based line of the row.
70
+ */
60
71
  /**
61
72
  * One `system.*` target the specification names for one note type.
62
73
  *
@@ -93,6 +104,12 @@ export const CONTENT_FORMAT_PATH: string;
93
104
  * @property {MappingClaim[]} claims - Every `system.*` target, in document order.
94
105
  * @property {Map<string, VocabularySpec>} vocabularies - Key → the values it
95
106
  * admits, for every closed vocabulary the document states as a table.
107
+ * @property {Map<string, DataRow>} [sharedDataRows] - The rows of the shared
108
+ * `data` property table — the keys every type accepts — by path. Read from a
109
+ * Markdown specification only.
110
+ * @property {Map<string, DataRow>} [eventRows] - The rows of the event key
111
+ * tables, by path from one event entry (`names[].by`). Read from a Markdown
112
+ * specification only.
96
113
  */
97
114
  /**
98
115
  * What a shared row's `noteType` reads, in place of a type name.
@@ -127,6 +144,11 @@ export type TypeSpec = {
127
144
  * - The declared paths, whole.
128
145
  */
129
146
  dataPaths: Set<string>;
147
+ /**
148
+ * - Each documented path's row, as
149
+ * a reference document states it. Read from a Markdown specification only.
150
+ */
151
+ dataRows?: Map<string, DataRow> | undefined;
130
152
  /**
131
153
  * - The declared `subType` values,
132
154
  * in document order — empty when it states none, which is the ordinary case
@@ -134,6 +156,24 @@ export type TypeSpec = {
134
156
  */
135
157
  subTypes: string[];
136
158
  };
159
+ /**
160
+ * One row of a `data` property table, as a reference document states it.
161
+ */
162
+ export type DataRow = {
163
+ /**
164
+ * - The second cell, the value's shape in words.
165
+ */
166
+ shape: string;
167
+ /**
168
+ * - The whole row as written, for a reader looking for
169
+ * a marker anywhere in it.
170
+ */
171
+ text: string;
172
+ /**
173
+ * - 1-based line of the row.
174
+ */
175
+ line: number;
176
+ };
137
177
  /**
138
178
  * One `system.*` target the specification names for one note type.
139
179
  */
@@ -212,4 +252,16 @@ export type ContentFormat = {
212
252
  * admits, for every closed vocabulary the document states as a table.
213
253
  */
214
254
  vocabularies: Map<string, VocabularySpec>;
255
+ /**
256
+ * - The rows of the shared
257
+ * `data` property table — the keys every type accepts — by path. Read from a
258
+ * Markdown specification only.
259
+ */
260
+ sharedDataRows?: Map<string, DataRow> | undefined;
261
+ /**
262
+ * - The rows of the event key
263
+ * tables, by path from one event entry (`names[].by`). Read from a Markdown
264
+ * specification only.
265
+ */
266
+ eventRows?: Map<string, DataRow> | undefined;
215
267
  };
@@ -176,11 +176,14 @@ export function imageSourcesIn(body: string): string[];
176
176
  * without any other pass noticing — see the Foundry address below. Omitted,
177
177
  * the config-free checks run alone, which is what lets a caller with no
178
178
  * repository to resolve still read a body.
179
+ * @param {boolean} [opts.generated] - Whether `body` is a note's generated
180
+ * sections, which name the build's own drawings under `generated/`; an
181
+ * author's text may not.
179
182
  * @returns {Array<{file: string, line: number, column: number|undefined,
180
183
  * severity: "error", message: string}>} One finding per defect, in source
181
184
  * order.
182
185
  */
183
- export function checkImages(body: string, file: string, { bodyLine, bodyColumn, lineMap, config }?: {
186
+ export function checkImages(body: string, file: string, { bodyLine, bodyColumn, lineMap, config, generated }?: {
184
187
  bodyLine?: number | undefined;
185
188
  bodyColumn?: number | undefined;
186
189
  lineMap?: {
@@ -188,6 +191,7 @@ export function checkImages(body: string, file: string, { bodyLine, bodyColumn,
188
191
  generated: boolean;
189
192
  }[] | undefined;
190
193
  config?: object | undefined;
194
+ generated?: boolean | undefined;
191
195
  }): Array<{
192
196
  file: string;
193
197
  line: number;
@@ -10,7 +10,14 @@
10
10
  * @param {string} markdown - The authored body.
11
11
  * @param {{source?: string, sqlTables?: object[], pageLists?: object[]}} [context] -
12
12
  * Prepared results.
13
- * @returns {{markdown: string, errors: object[], warnings: object[], lineMap: object[]}}
13
+ * A note's generated sections — see {@link module:engine/generated-sections} —
14
+ * are appended to the body first, from the `generated` text the preparation
15
+ * set on its results, and expanded with it.
16
+ *
17
+ * @returns {{markdown: string, errors: object[], warnings: object[], lineMap: object[],
18
+ * generatedFrom?: number}} `generatedFrom` is the 0-based line of the
19
+ * expanded body the generated sections start on, where there are any — what
20
+ * a surface reads to tell them from the author's text.
14
21
  */
15
22
  export function expandContentTables(markdown: string, { source, sqlTables, pageLists }?: {
16
23
  source?: string;
@@ -21,4 +28,5 @@ export function expandContentTables(markdown: string, { source, sqlTables, pageL
21
28
  errors: object[];
22
29
  warnings: object[];
23
30
  lineMap: object[];
31
+ generatedFrom?: number;
24
32
  };
@@ -0,0 +1,145 @@
1
+ /**
2
+ * One key inside a field's value.
3
+ *
4
+ * @typedef {object} InnerKeySpec
5
+ * @property {string} name - The key as an author writes it.
6
+ * @property {string} [kind] - Its value's shape: `string`, `date`, `number`,
7
+ * `integer`, `boolean`, `address`, `list`, `map`, `scalar-or-map`,
8
+ * `list-or-map` or `string-or-list` — see {@link fitsKind}. Absent, the check
9
+ * makes no claim about the value.
10
+ * @property {readonly string[]} [allowed] - The closed set a present value is
11
+ * one of, where the key takes a fixed word.
12
+ * @property {boolean} [verbatim] - The value is a symbol, such as a unit, and
13
+ * every surface shows it exactly as written, never recased.
14
+ * @property {string} shape - The shape in words, for a finding and the reference.
15
+ * @property {boolean} [required] - The key must be stated, with a value.
16
+ * @property {boolean} [nullable] - An explicit `null` states the key, for a
17
+ * required key whose null has a meaning of its own.
18
+ * @property {string} [label] - The infobox row label, where humanising the key
19
+ * reads wrongly.
20
+ * @property {string} describe - One line, for the author-facing reference.
21
+ * @property {readonly InnerKeySpec[]} [fields] - Its own keys, where it is a map.
22
+ * @property {object} [entries] - One entry, where it is a list of maps.
23
+ * @property {object} [values] - One value, where it is a map keyed by data.
24
+ */
25
+ /** Whether a value is a plain map rather than a list, an Address or a scalar. */
26
+ export function isPlainMap(value: any): boolean;
27
+ /**
28
+ * Whether a present value has a declared kind's shape.
29
+ *
30
+ * Shape alone: whether an Address resolves, or a word is in a closed set, is the
31
+ * field's own check's question. Lenient where YAML is ambiguous — `"12"` is a
32
+ * number, an emptied map arrives as `[]`, and a `date` may be the bare number
33
+ * YAML reads `720.1` as — and strict where it is not: a `string` is text, so a
34
+ * title or a description written as `5` is a finding rather than a value
35
+ * nothing reads as text. An `address` is one value or a parsed Address; what it
36
+ * names is the reference check's.
37
+ *
38
+ * @param {unknown} value - The authored value, not `undefined` or `null`.
39
+ * @param {string|undefined} kind - The declared kind.
40
+ * @returns {boolean} Whether it fits.
41
+ */
42
+ export function fitsKind(value: unknown, kind: string | undefined): boolean;
43
+ /**
44
+ * The entries of a map value, whatever form it reached the lint in.
45
+ *
46
+ * A map keyed by Address arrives as an {@link AddressEntries} once the note
47
+ * boundary has typed its keys; `sourceKey` is the text the file holds, so a
48
+ * finding locates on what the author wrote.
49
+ *
50
+ * @param {unknown} value - A map value.
51
+ * @returns {Array<[string, unknown]>} Its authored keys and values.
52
+ */
53
+ export function mapEntriesOf(value: unknown): Array<[string, unknown]>;
54
+ /**
55
+ * A field declaration as the tree its dotted names describe.
56
+ *
57
+ * `appearance.eye_color` and `appearance.hair_color` are two keys of one
58
+ * container, `appearance`, which is itself a map closed to them. Grouping them
59
+ * here is what lets one walk close the container and every field inside it.
60
+ *
61
+ * @param {readonly object[]} fields - The type's `data:` declaration.
62
+ * @returns {object[]} One spec per top-level key, a dotted group as a `map`
63
+ * whose `fields` are its members, with `grouped: true`.
64
+ */
65
+ export function topLevelSpecs(fields: readonly object[]): object[];
66
+ /**
67
+ * A path as a reader writes it: `data.routes[0].terrain`.
68
+ *
69
+ * @param {ReadonlyArray<string|number>} path - The path from the top of the frontmatter.
70
+ * @returns {string} The label.
71
+ */
72
+ export function pathLabel(path: ReadonlyArray<string | number>): string;
73
+ /**
74
+ * Check every declared field's value against its stated inner keys.
75
+ *
76
+ * Run by the frontmatter lint after the container check has refused undeclared
77
+ * top-level keys and checked each top-level field's own kind, so neither is
78
+ * repeated here.
79
+ *
80
+ * @param {object} note - The note: `file`, `raw` and parsed `fm`.
81
+ * @param {readonly object[]} fields - The type's `data:` declaration, shared
82
+ * fields included.
83
+ * @returns {object[]} Findings, `file:line:column` located on the key at fault.
84
+ */
85
+ export function checkDataKeys(note: object, fields: readonly object[]): object[];
86
+ /**
87
+ * One key inside a field's value.
88
+ */
89
+ export type InnerKeySpec = {
90
+ /**
91
+ * - The key as an author writes it.
92
+ */
93
+ name: string;
94
+ /**
95
+ * - Its value's shape: `string`, `date`, `number`,
96
+ * `integer`, `boolean`, `address`, `list`, `map`, `scalar-or-map`,
97
+ * `list-or-map` or `string-or-list` — see {@link fitsKind}. Absent, the check
98
+ * makes no claim about the value.
99
+ */
100
+ kind?: string | undefined;
101
+ /**
102
+ * - The closed set a present value is
103
+ * one of, where the key takes a fixed word.
104
+ */
105
+ allowed?: readonly string[] | undefined;
106
+ /**
107
+ * - The value is a symbol, such as a unit, and
108
+ * every surface shows it exactly as written, never recased.
109
+ */
110
+ verbatim?: boolean | undefined;
111
+ /**
112
+ * - The shape in words, for a finding and the reference.
113
+ */
114
+ shape: string;
115
+ /**
116
+ * - The key must be stated, with a value.
117
+ */
118
+ required?: boolean | undefined;
119
+ /**
120
+ * - An explicit `null` states the key, for a
121
+ * required key whose null has a meaning of its own.
122
+ */
123
+ nullable?: boolean | undefined;
124
+ /**
125
+ * - The infobox row label, where humanising the key
126
+ * reads wrongly.
127
+ */
128
+ label?: string | undefined;
129
+ /**
130
+ * - One line, for the author-facing reference.
131
+ */
132
+ describe: string;
133
+ /**
134
+ * - Its own keys, where it is a map.
135
+ */
136
+ fields?: readonly InnerKeySpec[] | undefined;
137
+ /**
138
+ * - One entry, where it is a list of maps.
139
+ */
140
+ entries?: object | undefined;
141
+ /**
142
+ * - One value, where it is a map keyed by data.
143
+ */
144
+ values?: object | undefined;
145
+ };
@@ -0,0 +1,73 @@
1
+ /**
2
+ * The places of this package that are given the map from them: each one that
3
+ * states, or is named in, a border or a route, and publishes a page.
4
+ *
5
+ * @param {object[]} records - The content-index records.
6
+ * @param {object} [opts]
7
+ * @param {Map<string, object>} [opts.foreignIndex] - The fetched indexes, whose
8
+ * places a local place's border or route may name.
9
+ * @param {object} [opts.config] - The resolved configuration. `site.maps:
10
+ * false` gives no place a map.
11
+ * @returns {string[]} The places' shortcodes, sorted.
12
+ */
13
+ export function placesWithMaps(records: object[], { foreignIndex, config }?: {
14
+ foreignIndex?: Map<string, object> | undefined;
15
+ config?: object | undefined;
16
+ }): string[];
17
+ /**
18
+ * Draw the map from each place given one, for a surface that serves the
19
+ * drawing as a file: the Foundry compile and the book. Each drawing is the
20
+ * standalone SVG `package-build map --from` writes, with no links, since
21
+ * neither surface follows a link inside a picture.
22
+ *
23
+ * @param {object[]} records - The content-index records.
24
+ * @param {object} opts
25
+ * @param {string} opts.outDir - Where to draw. Emptied first, so a place that
26
+ * lost its relations keeps no drawing from an earlier run.
27
+ * @param {Map<string, object>} [opts.foreignIndex] - The fetched indexes.
28
+ * @param {object} [opts.config] - The resolved configuration.
29
+ * @param {Iterable<string>} [opts.only] - The places to draw, of those given a
30
+ * map; absent, every one.
31
+ * @returns {{maps: Map<string, string>, findings: object[]}} Each drawing's
32
+ * file, keyed by the file name a **From here** section names, and what
33
+ * drawing found.
34
+ */
35
+ export function drawMapsFrom(records: object[], { outDir, foreignIndex, config, only }?: {
36
+ outDir: string;
37
+ foreignIndex?: Map<string, object> | undefined;
38
+ config?: object | undefined;
39
+ only?: Iterable<string> | undefined;
40
+ }): {
41
+ maps: Map<string, string>;
42
+ findings: object[];
43
+ };
44
+ /**
45
+ * The derived sections each note is given.
46
+ *
47
+ * @param {object[]} records - The content-index records, of the audience the
48
+ * surface publishes to.
49
+ * @param {object} opts
50
+ * @param {(record: object) => string} opts.fileOf - A record's note file, as
51
+ * prepared results are keyed.
52
+ * @param {Map<string, object>} [opts.foreignIndex] - The fetched indexes.
53
+ * @param {object} [opts.config] - The resolved configuration.
54
+ * @param {string} [opts.only] - One note file to give sections to; absent,
55
+ * every note.
56
+ * @returns {Map<string, Map<string, string>>} Note file to its sections, each
57
+ * keyed by its slug, for every note given at least one.
58
+ */
59
+ export function derivedSections(records: object[], { fileOf, foreignIndex, config, only }: {
60
+ fileOf: (record: object) => string;
61
+ foreignIndex?: Map<string, object> | undefined;
62
+ config?: object | undefined;
63
+ only?: string | undefined;
64
+ }): Map<string, Map<string, string>>;
65
+ /**
66
+ * The heading each kind of place is grouped under, in the order the place
67
+ * vocabulary declares its kinds. A kind the vocabulary does not declare is
68
+ * grouped after these by its own name, and a place stating no kind last, under
69
+ * **Other**.
70
+ *
71
+ * @type {Readonly<Record<string, string>>}
72
+ */
73
+ export const PLACE_KIND_LABELS: Readonly<Record<string, string>>;
@@ -223,6 +223,21 @@ export function positionOfYamlPath(text: string, keyPath: ReadonlyArray<string |
223
223
  * @returns {Array<string|number>} Its segments, sequence indices as numbers.
224
224
  */
225
225
  export function yamlKeyPath(field: string): Array<string | number>;
226
+ /**
227
+ * The scalar a note's frontmatter states at a path, **as the author wrote it**.
228
+ *
229
+ * A check reads a note whose Addresses are already resolved to their canonical
230
+ * form, so a finding quoting the value it holds would quote text the file does
231
+ * not contain. This reads the file instead, through the same parse
232
+ * {@link positionOfYamlPath} uses.
233
+ *
234
+ * @param {string} raw - The note's full contents, frontmatter included.
235
+ * @param {ReadonlyArray<string|number>} keyPath - Path to the node, from the
236
+ * top of the frontmatter.
237
+ * @returns {string|number|boolean|undefined} The scalar, or `undefined` where
238
+ * the path names no scalar.
239
+ */
240
+ export function frontmatterValueAt(raw: string, keyPath: ReadonlyArray<string | number>): string | number | boolean | undefined;
226
241
  /**
227
242
  * Where a key sits **inside a note's frontmatter fence**, addressed by path.
228
243
  *
@@ -0,0 +1,99 @@
1
+ /**
2
+ * @typedef {object} EventView
3
+ * @property {string} [id] - The event's `id`.
4
+ * @property {object} entry - The event entry as the index holds it.
5
+ * @property {object|null} when - Its resolved `when`, or `null`.
6
+ * @property {object|null} until - Its resolved `until`, or `null`.
7
+ */
8
+ /**
9
+ * @typedef {object} EventNote
10
+ * @property {string} target - The note's canonical Address.
11
+ * @property {EventView[]} events - Its events, in entry order.
12
+ * @property {Array<{slug: string, kind?: string}>} anchors - Every anchor it declares.
13
+ */
14
+ /**
15
+ * Every note's events, by Address, from this package's index records and the
16
+ * fetched indexes of its dependencies.
17
+ *
18
+ * @param {Iterable<Record<string, any>>} records - This package's content-index records.
19
+ * @param {object} [options]
20
+ * @param {string} [options.contentPackage] - The package a written Address
21
+ * without one defaults to.
22
+ * @param {Map<string, object>} [options.foreignIndex] - The merged fetched
23
+ * indexes, as `loadForeignIndexes` returns them.
24
+ * @param {object} [options.dates] - The reckoning context, for a record that
25
+ * carries no resolved dates.
26
+ * @returns {{note: (written: string) => EventNote|undefined,
27
+ * own: (fm: object) => EventNote|undefined}} The lookup: `note` from a
28
+ * written Address, anchor already removed, to the note it names, and `own`
29
+ * from a note of this package's frontmatter to that note.
30
+ */
31
+ export function eventNoteIndex(records: Iterable<Record<string, any>>, { contentPackage, foreignIndex, dates }?: {
32
+ contentPackage?: string | undefined;
33
+ foreignIndex?: Map<string, object> | undefined;
34
+ dates?: object | undefined;
35
+ }): {
36
+ note: (written: string) => EventNote | undefined;
37
+ own: (fm: object) => EventNote | undefined;
38
+ };
39
+ /**
40
+ * A date as a note prints one: in the era its own marker or qualifier names,
41
+ * where the reckoning knows that era, else as written — `~` kept either way.
42
+ *
43
+ * @param {unknown} written - The date as the event writes it.
44
+ * @param {object|null} date - The resolved date.
45
+ * @param {object} [dates] - The reckoning context.
46
+ * @returns {string} The printed date.
47
+ */
48
+ export function printEventDate(written: unknown, date: object | null, dates?: object): string;
49
+ /**
50
+ * One field of one event, as the text a reference prints, or why it cannot.
51
+ *
52
+ * @param {EventView} event - The event.
53
+ * @param {string} field - One of {@link EVENT_REFERENCE_FIELDS}.
54
+ * @param {object} [dates] - The reckoning context.
55
+ * @returns {{text: string}|{missing: true}} The text, or that the event states
56
+ * no such field.
57
+ */
58
+ export function eventFieldText(event: EventView, field: string, dates?: object): {
59
+ text: string;
60
+ } | {
61
+ missing: true;
62
+ };
63
+ /** The fields of an event an inline reference may print, in the order a message names them. */
64
+ export const EVENT_REFERENCE_FIELDS: readonly string[];
65
+ export type EventView = {
66
+ /**
67
+ * - The event's `id`.
68
+ */
69
+ id?: string | undefined;
70
+ /**
71
+ * - The event entry as the index holds it.
72
+ */
73
+ entry: object;
74
+ /**
75
+ * - Its resolved `when`, or `null`.
76
+ */
77
+ when: object | null;
78
+ /**
79
+ * - Its resolved `until`, or `null`.
80
+ */
81
+ until: object | null;
82
+ };
83
+ export type EventNote = {
84
+ /**
85
+ * - The note's canonical Address.
86
+ */
87
+ target: string;
88
+ /**
89
+ * - Its events, in entry order.
90
+ */
91
+ events: EventView[];
92
+ /**
93
+ * - Every anchor it declares.
94
+ */
95
+ anchors: Array<{
96
+ slug: string;
97
+ kind?: string;
98
+ }>;
99
+ };
@@ -0,0 +1,12 @@
1
+ /**
2
+ * The `events` rows of a set of index records.
3
+ *
4
+ * @param {Iterable<Record<string, any>>} records - Index records, every
5
+ * Address a string, already narrowed to the audience being published to.
6
+ * @returns {object[]} One row per event entry, in record then entry order.
7
+ */
8
+ export function eventRows(records: Iterable<Record<string, any>>): object[];
9
+ /** The sort keys a row carries, after the event's own keys. */
10
+ export const EVENT_SORT_COLUMNS: readonly string[];
11
+ /** Every column of the `events` relation, in order. */
12
+ export const EVENT_COLUMNS: any;