@heroiclands/package-build 22.25.0 → 22.27.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 (67) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/README.md +4 -0
  3. package/assets/styles/content-base.css +46 -3
  4. package/docs/api.md +35 -12
  5. package/docs/authoring/frontmatter.md +21 -0
  6. package/docs/authoring/links-and-markup.md +96 -149
  7. package/docs/content-format.md +6 -2
  8. package/docs/guides/government-migration.md +52 -0
  9. package/docs/guides/site.md +5 -5
  10. package/docs/reference/format-details.md +152 -246
  11. package/docs/reference/note-types.md +27 -28
  12. package/docs/reference/theme-pages.md +33 -29
  13. package/engine/anchors.mjs +85 -13
  14. package/engine/art-fields.mjs +1 -1
  15. package/engine/base-compiler.mjs +9 -1
  16. package/engine/bundles.mjs +1 -1
  17. package/engine/calendar-notes.mjs +1 -1
  18. package/engine/code-fences.mjs +6 -2
  19. package/engine/content-alerts.mjs +195 -0
  20. package/engine/content-blocks.mjs +119 -241
  21. package/engine/content-embeds.mjs +1 -1
  22. package/engine/content-figures.mjs +166 -230
  23. package/engine/content-format-check.mjs +3 -2
  24. package/engine/content-format.yaml +1 -5
  25. package/engine/content-images.mjs +3 -3
  26. package/engine/content-poetry.mjs +141 -0
  27. package/engine/content-spans.mjs +177 -0
  28. package/engine/foundry-entries.mjs +2 -0
  29. package/engine/frontmatter-lint.mjs +2 -1
  30. package/engine/heading-attributes.mjs +1 -1
  31. package/engine/helpers.mjs +8 -3
  32. package/engine/holdings.mjs +197 -333
  33. package/engine/index.mjs +1 -1
  34. package/engine/infobox.mjs +11 -1
  35. package/engine/journals.mjs +8 -6
  36. package/engine/markdown-expressions.mjs +9 -3
  37. package/engine/metadata-index.mjs +5 -3
  38. package/engine/note-vocabulary.mjs +30 -13
  39. package/engine/pdf-build.mjs +1 -1
  40. package/engine/pdf-render.mjs +90 -31
  41. package/engine/populations.mjs +17 -83
  42. package/engine/site-build.mjs +44 -16
  43. package/engine/site-preview.mjs +22 -6
  44. package/engine/wikilinks.mjs +18 -4
  45. package/hugo-theme/layouts/partials/holdings/entry.html +2 -2
  46. package/hugo-theme/layouts/partials/holdings.html +14 -14
  47. package/hugo-theme/static/css/style.css +40 -2
  48. package/package.json +1 -1
  49. package/sohl/item-fields.mjs +0 -16
  50. package/types/engine/anchors.d.mts +13 -4
  51. package/types/engine/art-fields.d.mts +1 -1
  52. package/types/engine/calendar-notes.d.mts +1 -1
  53. package/types/engine/code-fences.d.mts +3 -1
  54. package/types/engine/content-alerts.d.mts +62 -0
  55. package/types/engine/content-blocks.d.mts +3 -10
  56. package/types/engine/content-embeds.d.mts +1 -1
  57. package/types/engine/content-figures.d.mts +13 -20
  58. package/types/engine/content-images.d.mts +1 -1
  59. package/types/engine/content-poetry.d.mts +32 -0
  60. package/types/engine/content-spans.d.mts +18 -0
  61. package/types/engine/holdings.d.mts +75 -118
  62. package/types/engine/infobox.d.mts +1 -0
  63. package/types/engine/markdown-expressions.d.mts +1 -1
  64. package/types/engine/note-vocabulary.d.mts +14 -2
  65. package/types/engine/populations.d.mts +4 -13
  66. package/types/engine/site-build.d.mts +3 -3
  67. package/types/engine/wikilinks.d.mts +5 -1
@@ -0,0 +1,62 @@
1
+ /** Read alerts outside code examples, retaining inclusive source line ranges.
2
+ * @param {string} source - Authored Markdown.
3
+ */
4
+ export function scanAlerts(source: string): {
5
+ blocks: {
6
+ start: number;
7
+ end: number;
8
+ depth: number;
9
+ type: string;
10
+ title: any;
11
+ id: string;
12
+ classes: never[];
13
+ attributes: {
14
+ [k: string]: any;
15
+ };
16
+ body: string;
17
+ }[];
18
+ errors: {
19
+ line: number;
20
+ column: number;
21
+ message: string;
22
+ }[];
23
+ };
24
+ /** Render alert wrappers while preserving ordinary Markdown and note footnotes.
25
+ * @param {string} source - Authored Markdown.
26
+ * @param {"web"|"foundry"} [target="web"] - Publishing surface.
27
+ */
28
+ export function renderAlerts(source: string, target?: "web" | "foundry"): {
29
+ markdown: string;
30
+ errors: {
31
+ line: number;
32
+ column: number;
33
+ message: string;
34
+ }[];
35
+ };
36
+ /** Mark alert blockquotes and remove their marker before inline parsing.
37
+ * @param {import("markdown-it")} md - Markdown parser to extend.
38
+ */
39
+ export function alertMarkdownPlugin(md: typeof import("markdown-it")): void;
40
+ /** Alert titles and static icons shared by all publishing surfaces. */
41
+ export const ALERT_TYPES: Readonly<{
42
+ note: {
43
+ title: string;
44
+ icon: string;
45
+ svg: string;
46
+ };
47
+ tip: {
48
+ title: string;
49
+ icon: string;
50
+ svg: string;
51
+ };
52
+ important: {
53
+ title: string;
54
+ icon: string;
55
+ svg: string;
56
+ };
57
+ warning: {
58
+ title: string;
59
+ icon: string;
60
+ svg: string;
61
+ };
62
+ }>;
@@ -67,20 +67,13 @@ export function renderBlocks(source: string, target: "foundry" | "web"): {
67
67
  export function renderWithheldSections(source: string): string;
68
68
  /** The blocks an author may open, with the heading each takes by default. */
69
69
  export const BLOCK_NAMES: Readonly<{
70
- info: "Info";
71
70
  secret: "Secret";
72
- warn: "Warn";
73
71
  }>;
74
72
  /**
75
- * Blocks that may hold another named block.
73
+ * Container fences whose bodies are scanned and rendered recursively.
76
74
  *
77
- * A box inside a GM-only section is a real thing to write — the section is a
78
- * container for whatever the GM reads, boxes included — so a `secret` holds one
79
- * and the box stays inside it. A box inside a box is noise, so `info` and `warn`
80
- * hold no named block and a second opener inside one is a finding.
81
- *
82
- * Exported because a renderer has to know it: the body of a container is read
83
- * for blocks of its own, and the body of a box is not.
75
+ * A secret may hold general divs; a general div may hold another div or a
76
+ * secret. A secret nested directly within another secret is refused.
84
77
  *
85
78
  * @type {readonly string[]}
86
79
  */
@@ -49,7 +49,7 @@ export function resolveEmbed(index: object, embed: ParsedEmbed): {
49
49
  * The role an address's asset declares, read through the same resolution an
50
50
  * embed's address takes.
51
51
  *
52
- * This is the lookup a `:::figure` fence's `map` counter reaches through —
52
+ * This is the lookup a captioned item's `map` counter reaches through —
53
53
  * see {@link module:engine/content-figures.scanFigures}'s `resolveRole` — for
54
54
  * an address still in its authored form, before {@link resolveEmbeds} has
55
55
  * rewritten it into the ordinary image every surface renders.
@@ -1,21 +1,15 @@
1
1
  /** Number a sequence of figures with counters shared across documents. */
2
2
  export function numberFigures(figures: any, counts: any): any;
3
3
  /**
4
- * Read every `:::figure` fence in a body.
5
- *
6
- * SQL fences are expanded before this pass, so their output is a table.
7
- *
8
- * @param {string} source - A note body with expanded tables.
4
+ * Read leading captions and their following blocks outside literal fences.
5
+ * Historical figure API names remain for caption references and consumers.
6
+ * @param {string} source - The authored or expanded note body.
9
7
  * @param {object} [options] - Options.
10
- * @param {(address: string) => string|undefined} [options.resolveRole] - From
11
- * a picture's address to the role its asset declares, so a picture whose
12
- * asset declares `role: map` counts as `map` rather than `figure`. Omitted,
13
- * every picture counts as `figure` — the same reading a role other than
14
- * `map` gets.
8
+ * @param {(address: string) => string|undefined} [options.resolveRole] - Asset role lookup.
15
9
  * @returns {{figures: Array<{id: string, slug: string, caption: string,
16
- * hasCaption: boolean, classes: string[], kind: string, number: number,
17
- * label: string, line: number, bodyStart: number, bodyEnd: number,
18
- * captionStart: number, captionEnd: number, close: number}>,
10
+ * hasCaption: boolean, classes: string[], attributes: Record<string,string>,
11
+ * kind: string, numbered: boolean, number: number, label: string, line: number,
12
+ * bodyStart: number, bodyEnd: number, captionStart: number, captionEnd: number, close: number}>,
19
13
  * errors: Array<{line: number, column: number, message: string}>}}
20
14
  */
21
15
  export function scanFigures(source: string, { resolveRole }?: {
@@ -27,7 +21,9 @@ export function scanFigures(source: string, { resolveRole }?: {
27
21
  caption: string;
28
22
  hasCaption: boolean;
29
23
  classes: string[];
24
+ attributes: Record<string, string>;
30
25
  kind: string;
26
+ numbered: boolean;
31
27
  number: number;
32
28
  label: string;
33
29
  line: number;
@@ -44,7 +40,7 @@ export function scanFigures(source: string, { resolveRole }?: {
44
40
  }>;
45
41
  };
46
42
  /**
47
- * Render figure fences as HTML, leaving other Markdown untouched.
43
+ * Render leading captions and their next blocks as HTML, leaving other Markdown untouched.
48
44
  *
49
45
  * A code, table or prose figure's contents are left as Markdown inside the
50
46
  * wrapper, blank-line separated from its tags exactly as
@@ -84,6 +80,7 @@ export function renderFigureBlocks(source: string, renderMarkdown?: (markdown: s
84
80
  /** A figure's automatically determined kind, and the word that labels it. */
85
81
  export const FIGURE_NAMES: Readonly<{
86
82
  code: "Code";
83
+ example: "Example";
87
84
  table: "Table";
88
85
  figure: "Figure";
89
86
  map: "Map";
@@ -91,12 +88,8 @@ export const FIGURE_NAMES: Readonly<{
91
88
  prose: "Prose";
92
89
  }>;
93
90
  /**
94
- * The classes a figure takes.
95
- *
96
- * `.border` states that the captioned thing is drawn inside a border, and each
97
- * medium owns what that means. The vocabulary is closed: a class absent from it
98
- * is a finding naming the class.
99
- *
91
+ * Historical built-in presentation classes, retained for theme consumers.
92
+ * Captions now accept arbitrary classes through the shared attribute grammar.
100
93
  * @type {readonly string[]}
101
94
  */
102
95
  export const FIGURE_CLASSES: readonly string[];
@@ -67,7 +67,7 @@ export function escapeHtml(text: string): string;
67
67
  * function, so the two cannot drift into styling the same directive through
68
68
  * different class names.
69
69
  *
70
- * **No `<figcaption>` is emitted here.** A `:::figure` fence draws its own
70
+ * **No `<figcaption>` is emitted here.** A captioned item draws its own
71
71
  * label and authored caption around whatever this returns; the alt text stays
72
72
  * on the `img` element alone.
73
73
  *
@@ -17,3 +17,35 @@ export function inlineVerse(text: any): string;
17
17
  * definitions remain in scope. The span carries the indent for each line.
18
18
  */
19
19
  export function poetryMarkdown(body: any): string;
20
+ /** Read poetry code fences; start/end are inclusive zero-based source lines.
21
+ * @param {string} source - Authored Markdown.
22
+ */
23
+ export function scanPoetry(source: string): {
24
+ blocks: {
25
+ end: number;
26
+ body: string;
27
+ start: number;
28
+ fence: string;
29
+ name: string;
30
+ attributes: {};
31
+ id: string;
32
+ classes: never[];
33
+ indent: string;
34
+ }[];
35
+ errors: {
36
+ line: number;
37
+ column: number;
38
+ message: string;
39
+ }[];
40
+ };
41
+ /** Replace verse fences with HTML wrappers whose body remains inline Markdown.
42
+ * @param {string} source - Authored Markdown.
43
+ */
44
+ export function renderPoetry(source: string): {
45
+ markdown: string;
46
+ errors: {
47
+ line: number;
48
+ column: number;
49
+ message: string;
50
+ }[];
51
+ };
@@ -0,0 +1,18 @@
1
+ /** Add bracket spans after recognized Markdown links and footnotes.
2
+ * @param {import("markdown-it")} md - Markdown parser to extend.
3
+ */
4
+ export function spanMarkdownPlugin(md: typeof import("markdown-it")): void;
5
+ /** Read span anchors and located attribute diagnostics outside literal code.
6
+ * @param {string} source - Authored Markdown.
7
+ */
8
+ export function scanSpans(source: string): {
9
+ spans: any[];
10
+ errors: any[];
11
+ };
12
+ /** Emit span tags while leaving their inline content as Markdown for Hugo.
13
+ * @param {string} source - Authored Markdown.
14
+ */
15
+ export function renderSpans(source: string): {
16
+ markdown: string;
17
+ errors: any[];
18
+ };
@@ -1,157 +1,114 @@
1
+ /** @typedef {{title:string,url?:string,type:string,subType?:string}} HoldingsEntry */
1
2
  /**
2
- * A `parents` or `domains` value as the shortcodes it names, in order,
3
- * empties dropped and repeats collapsed.
4
- *
5
- * @param {unknown} value - The authored value — a list, or a lone entry.
6
- * @returns {string[]} The shortcodes.
3
+ * @typedef {object} HoldingsNode
4
+ * @property {string} shortcode
5
+ * @property {"place"|"affiliation"} type
6
+ * @property {string} [subType]
7
+ * @property {string} title
8
+ * @property {string} [url]
9
+ * @property {string} [package] Owning content package.
10
+ * @property {string} [system] Own document system.
11
+ * @property {string} [canonical] Full own Address.
12
+ * @property {string} [governmentSystem] Affiliation reference default system.
13
+ * @property {unknown[]} parents
14
+ * @property {unknown} [government] Null is explicit anarchy; absence is omission.
15
+ */
16
+ /** @typedef {{contains?:HoldingsEntry[],governed_by?:HoldingsEntry[],governed_places?:HoldingsEntry[]}} Holdings */
17
+ /** Historical shortcode projection for callers that explicitly need one.
18
+ * @param {unknown} value
19
+ * @returns {string[]}
7
20
  */
8
21
  export function shortcodesOf(value: unknown): string[];
9
- /**
10
- * Read a local note into a node, or `null` for a note that takes no part.
11
- *
12
- * @param {object} fm - The note's frontmatter.
13
- * @param {object} page - The page it publishes as.
14
- * @param {string} page.title - Its published title.
15
- * @param {string} page.url - Its URL.
16
- * @returns {HoldingsNode|null} The node, or `null` for a note that is neither
17
- * a place nor an affiliation, or that declares no shortcode.
22
+ /** Read local facts without converting government omission into anarchy.
23
+ * @param {object} fm
24
+ * @param {{title:string,url?:string,package?:string,system?:string,governmentSystem?:string}} page
25
+ * @returns {HoldingsNode|null}
18
26
  */
19
- export function holdingsNode(fm: object, { title, url }: {
27
+ export function holdingsNode(fm: object, { title, url, package: pkg, system, governmentSystem }: {
20
28
  title: string;
21
- url: string;
29
+ url?: string;
30
+ package?: string;
31
+ system?: string;
32
+ governmentSystem?: string;
22
33
  }): HoldingsNode | null;
23
- /**
24
- * Read a fetched index's places and affiliations as nodes.
25
- *
26
- * An entry carries what the producer's record stated — its name, `subType`,
27
- * `parents` and `domains` — and its page URL where the package publishes one.
28
- *
29
- * @param {Map<string, object>|undefined} foreignIndex - As
30
- * {@link module:engine/metadata-index.loadForeignIndexes} returns it.
31
- * @returns {HoldingsNode[]} The nodes, in index order.
32
- */
34
+ /** @param {Map<string,object>|undefined} foreignIndex @returns {HoldingsNode[]} */
33
35
  export function foreignHoldingsNodes(foreignIndex: Map<string, object> | undefined): HoldingsNode[];
34
- /**
35
- * Invert `parents` and `domains` into each page's lists.
36
- *
37
- * A shortcode is declared once per type: the first node declaring it wins,
38
- * so local nodes handed in ahead of fetched ones shadow a dependency's, the
39
- * way the link resolver answers. A node with no URL carries no lists of its
40
- * own, since there is no page to write them on — and is still an entry on
41
- * everybody else's, rendered as plain text. A name no node declares is
42
- * dropped: a `parents` naming nowhere is the map's finding, a `domains`
43
- * naming nowhere the reference check's.
44
- *
45
- * The result holds only pages with at least one entry on at least one list,
46
- * and a page's block carries only the keys it has entries for — the theme's
47
- * silent-disappear convention, kept at the source.
48
- *
49
- * @param {Iterable<HoldingsNode|null>} nodes - Every place and affiliation,
50
- * local first. `parents` and `domains` are read as written, so a node
51
- * built by hand may carry them as the note spells them.
52
- * @returns {Map<string, Holdings>} URL → the page's lists, sorted.
36
+ /** Invert direct place facts. A stub remains a plain text entry; a stub's own
37
+ * absent page receives no lists. First declaration of a page Address wins;
38
+ * different document systems for one page normalize to its `note` identity.
39
+ * @param {Iterable<HoldingsNode|null>} nodes
40
+ * @param {object} [options]
41
+ * @param {Iterable<HoldingsNode|null>} [options.governmentNodes] Additional public
42
+ * records without pages, participating only in government relationships.
43
+ * @returns {Map<string,Holdings>}
53
44
  */
54
- export function holdingsPages(nodes: Iterable<HoldingsNode | null>): Map<string, Holdings>;
45
+ export function holdingsPages(nodes: Iterable<HoldingsNode | null>, { governmentNodes }?: {
46
+ governmentNodes?: Iterable<HoldingsNode | null> | undefined;
47
+ }): Map<string, Holdings>;
55
48
  /**
56
- * Check a place note's tenure: a settlement, a site or a structure that no
57
- * affiliation's `domains` names is unheld land, reported as a warning at the
58
- * note's `type:` line.
59
- *
60
- * Declared on the `place` vocabulary as its type-level check, so the lint
61
- * runs it beside the field checks with the same index. Without an index the
62
- * question cannot be asked and nothing is reported.
49
+ * Advise when a place with an authored positive population omits government.
50
+ * Missing, null or zero population establishes no inhabited population.
51
+ * Property presence distinguishes omitted government from explicit null,
52
+ * which means complete anarchy. Non-null values are validated by the declared
53
+ * affiliation reference field. Neither geographic containment nor tenure
54
+ * supplies this fact, and the rule is independent of place subtype.
63
55
  *
64
- * @param {object} note - The note, as the link index hands it over.
65
- * @param {object} [opts]
66
- * @param {object} [opts.index] - The link index, holding every affiliation.
67
- * @returns {object[]} Findings.
56
+ * @param {object} note - The note with parsed frontmatter and raw source.
57
+ * @returns {object[]} Located warning findings.
68
58
  */
69
- export function checkHeld(note: object, { index }?: {
70
- index?: object | undefined;
71
- }): object[];
59
+ export function checkGovernment(note: object): object[];
72
60
  /**
73
- * The keys this module writes, and which a note cannot author: `contains`
74
- * and `held_by` on a place, `holdings` on an affiliation.
75
- *
61
+ * The historical API name for the government advisory. Tenure is no longer checked.
62
+ * @deprecated Use checkGovernment.
63
+ * @param {object} note - The place note.
64
+ * @param {object} [_opts] - Historical options, no longer needed.
65
+ * @returns {object[]} Government advisory findings.
66
+ */
67
+ export function checkHeld(note: object, _opts?: object): object[];
68
+ /** Derived keys, including retired keys removed from generated pages.
76
69
  * @type {readonly string[]}
77
70
  */
78
71
  export const HOLDINGS_KEYS: readonly string[];
79
- /**
80
- * The place subTypes tenure is checked on. A region is held through its
81
- * polity's `domains`, a world by nobody, a feature by nobody — a river has no
82
- * lord — so the rest are the kinds of place a body holds directly.
83
- *
72
+ /** @deprecated Government advisories apply to every inhabited place subtype.
84
73
  * @type {readonly string[]}
85
74
  */
86
75
  export const HELD_SUBTYPES: readonly string[];
87
- /**
88
- * One entry of a holdings list — a page a reader is pointed at.
89
- */
90
76
  export type HoldingsEntry = {
91
- /**
92
- * The page's published title.
93
- */
94
77
  title: string;
95
- /**
96
- * `<base><slug>/` — the page's address as every
97
- * href this build renders composes it. **Absent
98
- * for a stub**, which has no page: an entry with no
99
- * `url` renders as plain text.
100
- */
101
- url?: string | undefined;
102
- /**
103
- * The note's `type` — `place` or `affiliation`.
104
- */
78
+ url?: string;
105
79
  type: string;
106
- /**
107
- * The note's `subType`, where it declares one.
108
- */
109
- subType?: string | undefined;
80
+ subType?: string;
110
81
  };
111
- /**
112
- * One place or affiliation, as the derivation reads it — a local page or a
113
- * fetched index entry through one shape.
114
- */
115
82
  export type HoldingsNode = {
116
- /**
117
- * Lower case.
118
- */
119
83
  shortcode: string;
120
84
  type: "place" | "affiliation";
121
85
  subType?: string | undefined;
122
- /**
123
- * The page's published title.
124
- */
125
86
  title: string;
126
- /**
127
- * The page's URL; absent where the package
128
- * publishes no page for it.
129
- */
130
87
  url?: string | undefined;
131
88
  /**
132
- * What a place sits within, as written.
89
+ * Owning content package.
133
90
  */
134
- parents: string[];
91
+ package?: string | undefined;
135
92
  /**
136
- * What an affiliation holds, as written.
93
+ * Own document system.
137
94
  */
138
- domains: string[];
139
- };
140
- /**
141
- * The lists one page carries. Every key is optional, and a key present holds
142
- * at least one entry.
143
- */
144
- export type Holdings = {
95
+ system?: string | undefined;
145
96
  /**
146
- * Places whose `parents` name this one.
97
+ * Full own Address.
147
98
  */
148
- contains?: HoldingsEntry[] | undefined;
99
+ canonical?: string | undefined;
149
100
  /**
150
- * Affiliations whose `domains` name this one.
101
+ * Affiliation reference default system.
151
102
  */
152
- held_by?: HoldingsEntry[] | undefined;
103
+ governmentSystem?: string | undefined;
104
+ parents: unknown[];
153
105
  /**
154
- * Places this affiliation's `domains` name.
106
+ * Null is explicit anarchy; absence is omission.
155
107
  */
156
- holdings?: HoldingsEntry[] | undefined;
108
+ government?: unknown;
109
+ };
110
+ export type Holdings = {
111
+ contains?: HoldingsEntry[];
112
+ governed_by?: HoldingsEntry[];
113
+ governed_places?: HoldingsEntry[];
157
114
  };
@@ -27,6 +27,7 @@ export function isUnsetSentinel(value: unknown): boolean;
27
27
  /**
28
28
  * Whether a value is worth a row.
29
29
  *
30
+ * A field declaring `nullText` handles explicit null before this general test.
30
31
  * Rule 4: an absent field is absent. `null`, `""` and `[]` are how the corpus
31
32
  * writes "nobody filled this in" — a note that declares every key of its type
32
33
  * and leaves most of them empty is the ordinary shape, not the exception — and
@@ -9,7 +9,7 @@ export function sqlQueriesInMarkdown(body: any, fm?: {}): any[];
9
9
  * {url: string|null, figures: Map<string, object>}|undefined,
10
10
  * link?: Function}, file?: string, bodyLine?: number}} [options] -
11
11
  * `figures` is the `ref` helper's own view of the corpus: `get` reads this
12
- * note's `:::figure` fences by id, and `note` resolves another note's the
12
+ * note's captioned items by id, and `note` resolves another note's the
13
13
  * way a wikilink would — omitted, a cross-note address is refused rather
14
14
  * than looked up. `link` overrides how a resolved reference renders; the
15
15
  * default is a Markdown link to the target's own anchor.
@@ -133,6 +133,15 @@ export function dataFields(type: string, vocabulary?: Readonly<Record<string, Ty
133
133
  * it has no `subType` at all — see {@link TypeVocabulary}.
134
134
  */
135
135
  export function subTypes(type: string, vocabulary?: Readonly<Record<string, TypeVocabulary>>): readonly string[] | null | undefined;
136
+ /**
137
+ * Accepted migration input with no canonical field or emitted value.
138
+ *
139
+ * Legacy affiliation domains are ignored. They never supply a government.
140
+ * @param {string} type - The note type.
141
+ * @param {string} key - An authored data key.
142
+ * @returns {boolean} Whether the obsolete key is accepted during migration.
143
+ */
144
+ export function isLegacyDataField(type: string, key: string): boolean;
136
145
  /**
137
146
  * One top-level frontmatter key.
138
147
  *
@@ -380,6 +389,10 @@ export type DataFieldSpec = {
380
389
  * - Allowed Address types, separate from `ref`.
381
390
  */
382
391
  accepts?: readonly string[] | undefined;
392
+ /**
393
+ * - Infobox text for an explicitly authored null with a declared meaning.
394
+ */
395
+ nullText?: string | undefined;
383
396
  /**
384
397
  * - Human-readable shape, for a finding and for
385
398
  * documentation.
@@ -464,8 +477,7 @@ export type TypeVocabulary = {
464
477
  * - A
465
478
  * check of the whole note, run by the frontmatter lint beside the field
466
479
  * checks with the same index. For a rule that is about the note rather than
467
- * one of its fields — a place's tenure is a fact about every affiliation's
468
- * `domains`, and is located at the note's `type:` line.
480
+ * one of its fields, located at the note's `type:` line.
469
481
  */
470
482
  check?: ((note: object, opts: {
471
483
  index?: object;
@@ -16,7 +16,7 @@ export function foreignNode(canonical: string, entry: object): PopulationNode |
16
16
  * runs it with the index every reference check resolves through. Without an
17
17
  * index the questions cannot be asked and nothing is reported.
18
18
  *
19
- * Three rules, each reported on the note being linted: `over-held land` and
19
+ * Two geographical rules, each reported on the note being linted:
20
20
  * `over-full region` on the place whose figure is exceeded, and
21
21
  * `oversized settlement` on the settlement that exceeds one.
22
22
  *
@@ -35,8 +35,8 @@ export function checkPopulation(note: object, { index }?: {
35
35
  * restated figures drift. Each is located at the figure it wrote, counting
36
36
  * repeats so two rows carrying one number land on their own lines.
37
37
  *
38
- * A citation naming a note this package does not hold is skipped: a fetched
39
- * index carries no figure, so there is nothing to disagree with.
38
+ * A citation naming a note with no published population figure is skipped:
39
+ * there is nothing to disagree with.
40
40
  *
41
41
  * Declared as the `doc` vocabulary's type-level check.
42
42
  *
@@ -97,13 +97,9 @@ export type PopulationNode = {
97
97
  * superiors.
98
98
  */
99
99
  parents: string[];
100
- /**
101
- * What an affiliation holds.
102
- */
103
- domains: string[];
104
100
  };
105
101
  /**
106
- * The whole tree, indexed the three ways the rules read it.
102
+ * The whole tree, indexed by place, affiliation and geographical parent.
107
103
  */
108
104
  export type Corpus = {
109
105
  /**
@@ -119,11 +115,6 @@ export type Corpus = {
119
115
  * whose `parents` name it.
120
116
  */
121
117
  childrenOf: Map<string, string[]>;
122
- /**
123
- * Place shortcode → the polities
124
- * whose `domains` name it.
125
- */
126
- holdersOf: Map<string, string[]>;
127
118
  /**
128
119
  * `type/shortcode` → the
129
120
  * node, for the citation rule.
@@ -182,7 +182,7 @@ export function tableUniverse(pages: object[]): Map<string, object[]>;
182
182
  * about every other page, known only once the whole tree has resolved — see
183
183
  * {@link module:engine/related-pages} — so an authored value is dropped the
184
184
  * way `aliases` is, and {@link renderPages} writes the derived block once it
185
- * holds the graph. `contains`, `held_by` and `holdings` are dropped for the
185
+ * holds the graph. Derived geographical and government lists are dropped for the
186
186
  * same reason — see {@link module:engine/holdings}. **So is `map`**: the
187
187
  * file a place page names is the one the build drew beside it — see
188
188
  * {@link module:engine/site-maps} — and a page with no drawing names none.
@@ -258,8 +258,8 @@ export function renderSitePage(page: any, { index, foreign, universe, pass, deco
258
258
  secretErrors: {
259
259
  file: any;
260
260
  line: number;
261
- column: number;
262
- message: string;
261
+ column: any;
262
+ message: any;
263
263
  }[];
264
264
  captionErrors: {
265
265
  file: any;
@@ -18,7 +18,8 @@ export function anchorPageId(noteId: string, anchorSlug: string): string;
18
18
  *
19
19
  * @param {Array<{type: string, id: string, shortcode?: string|null,
20
20
  * name?: string, pack?: string, docPack?: string, none?: boolean,
21
- * draft?: boolean}>} docs -
21
+ * draft?: boolean, anchors?: Set<string>, anchorUuids?: Record<string,string>,
22
+ * docAnchorUuids?: Record<string,string>}>} docs -
22
23
  * One entry per content note. `pack` / `docPack` name the packs the note's
23
24
  * document and its documentation entry landed in; omitted, the conventional
24
25
  * one-pack-per-type names stand in. `none` says the note declares
@@ -54,6 +55,9 @@ export function buildWikilinkIndex(docs: Array<{
54
55
  docPack?: string;
55
56
  none?: boolean;
56
57
  draft?: boolean;
58
+ anchors?: Set<string>;
59
+ anchorUuids?: Record<string, string>;
60
+ docAnchorUuids?: Record<string, string>;
57
61
  }>, packageId: string, foreign?: Map<string, object>, contentPackage?: string, { assets, noIndexPackages, referenceTargets, foreignReferences }?: {
58
62
  assets?: Map<string, object> | undefined;
59
63
  noIndexPackages?: Set<string> | undefined;