@heroiclands/package-build 23.2.2 → 23.3.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@heroiclands/package-build",
3
- "version": "23.2.2",
3
+ "version": "23.3.1",
4
4
  "description": "Shared toolchain for building and shipping a HeroicLands Foundry VTT package — content compilation, manifest, localization, staging, bundle, release and deployment.",
5
5
  "license": "GPL-3.0-or-later",
6
6
  "type": "module",
package/types/e2e.d.mts CHANGED
@@ -208,15 +208,19 @@ export function deployForContainer({ config, env, log, runScript, }: {
208
208
  * @param {string} opts.url - The container's base URL.
209
209
  * @param {string} opts.container - The container name, for its log.
210
210
  * @param {string} opts.stage - The stage, named in a licence failure.
211
+ * @param {string} [opts.dataRoot] - The stage's data root, named when its licence is unsigned.
212
+ * @param {(container: string) => string} [opts.readLog] - Reads the container's log since it started.
211
213
  * @param {number} [opts.timeoutMs] - How long to wait.
212
214
  * @param {(message: string) => void} [opts.log] - Progress reporting.
213
215
  * @returns {Promise<void>} Resolves once the world is active.
214
216
  * @throws {Error} On a licence failure or a timeout.
215
217
  */
216
- export function waitForWorld({ url, container, stage, timeoutMs, log }: {
218
+ export function waitForWorld({ url, container, stage, dataRoot, readLog, timeoutMs, log, }: {
217
219
  url: string;
218
220
  container: string;
219
221
  stage: string;
222
+ dataRoot?: string | undefined;
223
+ readLog?: ((container: string) => string) | undefined;
220
224
  timeoutMs?: number | undefined;
221
225
  log?: ((message: string) => void) | undefined;
222
226
  }): Promise<void>;
@@ -0,0 +1,94 @@
1
+ /**
2
+ * The genders every profile states a height range for.
3
+ *
4
+ * A function as well as a constant: `note-vocabulary.mjs` reads it while the
5
+ * module graph is still evaluating, before any `const` here is initialised,
6
+ * and a function declaration is bound from the start.
7
+ *
8
+ * @returns {readonly string[]} The genders.
9
+ */
10
+ export function requiredHeightGenders(): readonly string[];
11
+ /**
12
+ * The profile keys that take weighted words, read from the vocabulary: every
13
+ * being-look field but `gender`, by its last segment.
14
+ *
15
+ * @param {Readonly<Record<string, readonly {value: string}[]>>} lookVocabulary
16
+ * @returns {string[]} The keys, in the vocabulary's order.
17
+ */
18
+ export function profileLookKeys(lookVocabulary: Readonly<Record<string, readonly {
19
+ value: string;
20
+ }[]>>): string[];
21
+ /**
22
+ * Everything wrong with a profile.
23
+ *
24
+ * @param {unknown} profile - The profile as authored.
25
+ * @param {Readonly<Record<string, readonly {value: string}[]>>} lookVocabulary -
26
+ * The being-look vocabulary.
27
+ * @returns {ProfileProblem[]} The problems, in the order a reader meets them.
28
+ */
29
+ export function profileProblems(profile: unknown, lookVocabulary: Readonly<Record<string, readonly {
30
+ value: string;
31
+ }[]>>): ProfileProblem[];
32
+ /**
33
+ * The frontmatter lint's check of `data.appearanceProfile`.
34
+ *
35
+ * Scoped to a `lore` note of `subType: culture`: on any other lore it is an
36
+ * error at the key. On a culture it reports what the field's declared inner
37
+ * keys cannot: words outside the vocabulary, weights that are not positive, a
38
+ * word map with no words, height ranges that are unreadable, reversed or keyed
39
+ * by no gender, and a missing `female` or `male` range.
40
+ *
41
+ * @param {object} note - The note: `file`, `raw` and parsed `fm`.
42
+ * @param {Readonly<Record<string, readonly {value: string}[]>>} lookVocabulary -
43
+ * The being-look vocabulary.
44
+ * @returns {object[]} Findings, located at the word, weight or key at fault.
45
+ */
46
+ export function checkAppearanceProfile(note: object, lookVocabulary: Readonly<Record<string, readonly {
47
+ value: string;
48
+ }[]>>): object[];
49
+ /**
50
+ * A profile's problems as findings at the culture note that states it, for a
51
+ * caller holding the note but not running the lint.
52
+ *
53
+ * @param {object} note - The culture note: `file`, `raw` and parsed `fm`.
54
+ * @param {Readonly<Record<string, readonly {value: string}[]>>} lookVocabulary -
55
+ * The being-look vocabulary.
56
+ * @returns {object[]} Every problem, shape included, as findings.
57
+ */
58
+ export function profileFindings(note: object, lookVocabulary: Readonly<Record<string, readonly {
59
+ value: string;
60
+ }[]>>): object[];
61
+ /** The `lore` subType whose notes may carry a profile. */
62
+ export const PROFILE_SUBTYPE: "culture";
63
+ /** The genders every profile states a height range for. */
64
+ export const REQUIRED_HEIGHT_GENDERS: readonly string[];
65
+ /**
66
+ * The body-mass index band, in kg/m², each frame word means, lightest to
67
+ * heaviest. The bands meet end to end, so every weight at a given height falls
68
+ * in exactly one frame.
69
+ *
70
+ * @type {Readonly<Record<string, readonly [number, number]>>}
71
+ */
72
+ export const FRAME_MASS_INDEX: Readonly<Record<string, readonly [number, number]>>;
73
+ /**
74
+ * One thing wrong with a profile.
75
+ */
76
+ export type ProfileProblem = {
77
+ /**
78
+ * - Where, from the profile itself.
79
+ */
80
+ path: Array<string | number>;
81
+ /**
82
+ * - The fault is the key at `path`, not its value.
83
+ */
84
+ key?: boolean | undefined;
85
+ /**
86
+ * - The frontmatter lint's inner-key walk reports
87
+ * this too, from the field's declaration.
88
+ */
89
+ shape?: boolean | undefined;
90
+ /**
91
+ * - What is wrong, naming the full `data.` path.
92
+ */
93
+ message: string;
94
+ };
@@ -5,7 +5,7 @@
5
5
  * @property {string} name - The key as an author writes it.
6
6
  * @property {string} [kind] - Its value's shape: `string`, `date`, `number`,
7
7
  * `integer`, `boolean`, `address`, `list`, `map`, `scalar-or-map`,
8
- * or `string-or-list` — see {@link fitsKind}. Absent, the check
8
+ * `string-or-list`, or `string-list-or-map` — see {@link fitsKind}. Absent, the check
9
9
  * makes no claim about the value.
10
10
  * @property {readonly string[]} [allowed] - The closed set a present value is
11
11
  * one of, where the key takes a fixed word.
@@ -94,7 +94,7 @@ export type InnerKeySpec = {
94
94
  /**
95
95
  * - Its value's shape: `string`, `date`, `number`,
96
96
  * `integer`, `boolean`, `address`, `list`, `map`, `scalar-or-map`,
97
- * or `string-or-list` — see {@link fitsKind}. Absent, the check
97
+ * `string-or-list`, or `string-list-or-map` — see {@link fitsKind}. Absent, the check
98
98
  * makes no claim about the value.
99
99
  */
100
100
  kind?: string | undefined;
@@ -22,6 +22,7 @@ export * as placeRelations from "./place-relations.mjs";
22
22
  export * as holdings from "./holdings.mjs";
23
23
  export * as populations from "./populations.mjs";
24
24
  export * as marketClass from "./market-class.mjs";
25
+ export * as settlementTables from "./settlement-tables.mjs";
25
26
  export * as mapPlaces from "./map-places.mjs";
26
27
  export * as mapLayout from "./map-layout.mjs";
27
28
  export * as mapDot from "./map-dot.mjs";
@@ -50,7 +50,7 @@ export function hasValue(value: unknown): boolean;
50
50
  */
51
51
  export function humanizeFieldName(name: string): string;
52
52
  /**
53
- * An enumerated value as a reader sees it: `graying_brown` → `graying brown`.
53
+ * An enumerated value as a reader sees it: `greying_brown` → `greying brown`.
54
54
  *
55
55
  * @param {unknown} value - The authored value.
56
56
  * @returns {string} The text.
@@ -0,0 +1,140 @@
1
+ /**
2
+ * The genders every `data.names.given` states a list for.
3
+ *
4
+ * A function rather than a `const`: `note-vocabulary.mjs` reads it while the
5
+ * module graph is still evaluating.
6
+ *
7
+ * @returns {readonly string[]} The genders.
8
+ */
9
+ export function requiredGivenGenders(): readonly string[];
10
+ /**
11
+ * A pattern read into literal text and placeholders.
12
+ *
13
+ * @param {string} pattern - The pattern as written.
14
+ * @returns {{parts: PatternPart[], problems: string[]}} The parts, and what is
15
+ * wrong with the pattern's own spelling.
16
+ */
17
+ export function parsePattern(pattern: string): {
18
+ parts: PatternPart[];
19
+ problems: string[];
20
+ };
21
+ /**
22
+ * The patterns a name of `gender` may take: every pattern where they are not
23
+ * keyed by gender, the gender's own where it has some, else every pattern
24
+ * stated.
25
+ *
26
+ * @param {object} names - Checked `data.names`.
27
+ * @param {string} gender - A gender word.
28
+ * @returns {string[]} The patterns.
29
+ */
30
+ export function patternsFor(names: object, gender: string): string[];
31
+ /**
32
+ * Everything wrong with a language's name lists.
33
+ *
34
+ * @param {unknown} names - `data.names` as authored.
35
+ * @param {Readonly<Record<string, readonly {value: string}[]>>} lookVocabulary -
36
+ * The being-look vocabulary, whose `gender` words key `given`.
37
+ * @returns {NamesProblem[]} The problems, in the order a reader meets them.
38
+ */
39
+ export function namesProblems(names: unknown, lookVocabulary: Readonly<Record<string, readonly {
40
+ value: string;
41
+ }[]>>): NamesProblem[];
42
+ /**
43
+ * The frontmatter lint's check of `data.names`.
44
+ *
45
+ * Scoped to a `skill` note of `subType: language`: on any other skill it is an
46
+ * error at the key. On a language it reports what the field's declared inner
47
+ * keys cannot: a pattern that does not parse, a placeholder naming no list, a
48
+ * list no pattern names, a list name a placeholder cannot spell, an empty list
49
+ * of patterns or of names, an empty name, a pattern or given list keyed by no
50
+ * gender, and a missing `female` or `male` list. Each is located at the pattern, list, entry or key at fault.
51
+ *
52
+ * @param {object} note - The note: `file`, `raw` and parsed `fm`.
53
+ * @param {Readonly<Record<string, readonly {value: string}[]>>} lookVocabulary -
54
+ * The being-look vocabulary.
55
+ * @returns {object[]} Findings.
56
+ */
57
+ export function checkLanguageNames(note: object, lookVocabulary: Readonly<Record<string, readonly {
58
+ value: string;
59
+ }[]>>): object[];
60
+ /**
61
+ * A language's name-list problems as findings at the note that states them,
62
+ * shape included, for a caller holding the note but not running the lint.
63
+ *
64
+ * @param {object} note - The language note: `file`, `raw` and parsed `fm`.
65
+ * @param {Readonly<Record<string, readonly {value: string}[]>>} lookVocabulary -
66
+ * The being-look vocabulary.
67
+ * @returns {object[]} Every problem, as findings.
68
+ */
69
+ export function namesFindings(note: object, lookVocabulary: Readonly<Record<string, readonly {
70
+ value: string;
71
+ }[]>>): object[];
72
+ /**
73
+ * The given names a gender draws from: its own list, or every given list
74
+ * together where it has none.
75
+ *
76
+ * @param {object} names - Checked `data.names`.
77
+ * @param {string} gender - A gender word.
78
+ * @returns {string[]} The names.
79
+ */
80
+ export function givenNames(names: object, gender: string): string[];
81
+ /**
82
+ * A name drawn from a language's lists: one of the gender's patterns, where it
83
+ * has more than one, then each placeholder an even draw from its list.
84
+ *
85
+ * @param {object} names - Checked `data.names`.
86
+ * @param {string} gender - A gender word.
87
+ * @param {() => number} next - A stream of numbers in `[0, 1)`.
88
+ * @returns {string} The name.
89
+ */
90
+ export function drawName(names: object, gender: string, next: () => number): string;
91
+ /**
92
+ * Why a name does not fit a language's lists, or `undefined` where it fits.
93
+ *
94
+ * A name fits when it takes one of the patterns for `gender`, with every
95
+ * placeholder filled by a name of its list: `{given}` from the gender's given
96
+ * list, `{given.<gender>}` from that gender's. Names compare in Unicode NFC, so
97
+ * a precomposed and a decomposed accent are one letter.
98
+ *
99
+ * @param {string} full - The name as given.
100
+ * @param {object} names - Checked `data.names`.
101
+ * @param {string} gender - A gender word.
102
+ * @returns {string|undefined} One sentence naming the part that does not fit.
103
+ */
104
+ export function nameMisfit(full: string, names: object, gender: string): string | undefined;
105
+ /** The `skill` subType whose notes may carry name lists. */
106
+ export const NAMES_SUBTYPE: "language";
107
+ /** The placeholder that draws from the given-name list for a gender. */
108
+ export const GIVEN_LIST: "given";
109
+ /**
110
+ * One piece of a parsed pattern: literal text, or a placeholder naming a list
111
+ * and, for `given`, the gender whose list it draws from.
112
+ */
113
+ export type PatternPart = {
114
+ literal: string;
115
+ } | {
116
+ list: string;
117
+ gender?: string;
118
+ };
119
+ /**
120
+ * One thing wrong with a language's name lists.
121
+ */
122
+ export type NamesProblem = {
123
+ /**
124
+ * - Where, from `data.names` itself.
125
+ */
126
+ path: Array<string | number>;
127
+ /**
128
+ * - The fault is the key at `path`, not its value.
129
+ */
130
+ key?: boolean | undefined;
131
+ /**
132
+ * - The frontmatter lint's inner-key walk reports
133
+ * this too, from the field's declaration.
134
+ */
135
+ shape?: boolean | undefined;
136
+ /**
137
+ * - What is wrong, naming the full `data.` path.
138
+ */
139
+ message: string;
140
+ };
@@ -13,16 +13,27 @@ export function checkLanguageChoice(note: object, { index }?: {
13
13
  index?: object;
14
14
  }): object[];
15
15
  /**
16
- * Refuse a literature field on a lore note of any other subType.
16
+ * Refuse a literature field on a lore note of any other subType, and
17
+ * `data.language` on a lore note that is neither a work nor a culture.
17
18
  *
18
19
  * @param {object} note
19
- * @returns {object[]} One error per literature key written off `literature`.
20
+ * @returns {object[]} One error per key written off the subTypes that take it.
20
21
  */
21
22
  export function checkLiteratureNote(note: object): object[];
22
23
  /** The `lore` subType whose notes are works of literature. */
23
24
  export const LITERATURE_SUBTYPE: "literature";
25
+ /** The `lore` subTypes that may name a language. */
26
+ export const LANGUAGE_SUBTYPES: readonly string[];
24
27
  /**
25
- * The fields only a `literature` note may state. Every one is optional.
28
+ * `data.language`: the tongue a work is composed in, or the tongue a culture's
29
+ * people speak. Optional on both.
30
+ *
31
+ * @type {object}
32
+ */
33
+ export const LANGUAGE_FIELD: object;
34
+ /**
35
+ * The fields only a `literature` note may state, beside the shared
36
+ * {@link LANGUAGE_FIELD}. Every one is optional.
26
37
  *
27
38
  * @type {ReadonlyArray<object>}
28
39
  */
@@ -130,6 +130,19 @@ export function dataFields(type: string, vocabulary?: Readonly<Record<string, Ty
130
130
  * it has no `subType` at all — see {@link TypeVocabulary}.
131
131
  */
132
132
  export function subTypes(type: string, vocabulary?: Readonly<Record<string, TypeVocabulary>>): readonly string[] | null | undefined;
133
+ /**
134
+ * The words a being's look is stated in, keyed by the `data:` field that takes
135
+ * them.
136
+ *
137
+ * Each field is closed to its list: any other value, an empty one included, is
138
+ * a finding at the value naming the words it takes. `appearance.complexion`
139
+ * takes one word or a list of them, and each entry is checked on its own.
140
+ * `appearance.extra_features` is not here: it is free text, a list of the marks
141
+ * no word covers.
142
+ *
143
+ * @type {Readonly<Record<string, readonly LookWord[]>>}
144
+ */
145
+ export const BEING_LOOK_VOCABULARY: Readonly<Record<string, readonly LookWord[]>>;
133
146
  /**
134
147
  * What happened to or at a subject — the `events` key, declared once and spread
135
148
  * into every type that carries events, so the schema cannot differ between
@@ -333,6 +346,24 @@ export const BEING_ARCHETYPES: Readonly<{
333
346
  * @type {Readonly<Record<string, TypeVocabulary>>}
334
347
  */
335
348
  export const NOTE_VOCABULARY: Readonly<Record<string, TypeVocabulary>>;
349
+ /**
350
+ * One word of a closed vocabulary: the value a note writes, the label a reader
351
+ * sees it by, and what it means.
352
+ */
353
+ export type LookWord = {
354
+ /**
355
+ * - The word as a note writes it.
356
+ */
357
+ value: string;
358
+ /**
359
+ * - The word as a reader sees it.
360
+ */
361
+ label: string;
362
+ /**
363
+ * - What it means, in one line.
364
+ */
365
+ describe: string;
366
+ };
336
367
  /**
337
368
  * One `data:` key a note type may carry.
338
369
  *
@@ -0,0 +1,124 @@
1
+ /**
2
+ * A value as JSON with every map's keys sorted, so two specs stating the same
3
+ * fields in a different order serialise alike.
4
+ *
5
+ * @param {unknown} value - A spec, or any value in one.
6
+ * @returns {string} The canonical serialisation.
7
+ */
8
+ export function canonicalSpec(value: unknown): string;
9
+ /**
10
+ * Why a spec cannot be generated from, or nothing.
11
+ *
12
+ * @param {unknown} spec - The spec as read.
13
+ * @returns {string[]} One sentence per problem.
14
+ */
15
+ export function npcSpecProblems(spec: unknown): string[];
16
+ /**
17
+ * The shortcode a name derives, free of every shortcode in `taken`.
18
+ *
19
+ * @param {string} name - `name.full`.
20
+ * @param {ReadonlySet<string>} taken - Shortcodes the package's beings hold.
21
+ * @returns {string} The shortcode.
22
+ */
23
+ export function npcShortcode(name: string, taken: ReadonlySet<string>): string;
24
+ /**
25
+ * The Appearance section's paragraph, in the Folk wording: "Ahmetega Zekar is
26
+ * a 39-year-old man who stands 6'4" tall with a heavy build. He has tawny
27
+ * skin, weathered complexion, black hair, and brown eyes."
28
+ *
29
+ * A fact that is absent leaves its clause out.
30
+ *
31
+ * @param {object} facts
32
+ * @param {string} facts.name - `name.full`.
33
+ * @param {number|null} [facts.age] - Whole years, or `null` where unknown.
34
+ * @param {string} [facts.gender]
35
+ * @param {unknown} [facts.height]
36
+ * @param {string} [facts.frame]
37
+ * @param {object} [facts.appearance] - The `data.appearance` map.
38
+ * @returns {string} The paragraph.
39
+ */
40
+ export function appearanceParagraph({ name, age, gender, height, frame, appearance }: {
41
+ name: string;
42
+ age?: number | null | undefined;
43
+ gender?: string | undefined;
44
+ height?: unknown;
45
+ frame?: string | undefined;
46
+ appearance?: object | undefined;
47
+ }): string;
48
+ /**
49
+ * Generate a being note from a spec.
50
+ *
51
+ * @param {object} spec - The spec: frontmatter fields, plus `appearance` and
52
+ * `dossier` section bodies.
53
+ * @param {object} context
54
+ * @param {object} context.profile - The culture's appearance profile, already
55
+ * checked by `profileProblems`.
56
+ * @param {object} context.names - The language's `data.names`, already checked
57
+ * by `namesProblems`.
58
+ * @param {string} [context.language] - The language's Address, for an error
59
+ * about a name that does not fit.
60
+ * @param {string} [context.seed] - Text joined to the spec's own seed, to draw a
61
+ * different person from the same spec.
62
+ * @param {unknown} [context.present] - The package's present, or `null`.
63
+ * @param {object} [context.dateContext] - The reckoning context the present
64
+ * and `born` are read in, with `daysPerYear`.
65
+ * @param {{icon?: unknown, species?: unknown, packFolder?: unknown}} [context.defaults] -
66
+ * Values derived from the package's other beings.
67
+ * @param {ReadonlySet<string>} [context.taken] - Shortcodes the package's beings hold.
68
+ * @returns {{frontmatter: object, body: string, text: string}} The note.
69
+ * @throws {Error} Where the spec has problems, or states a `name.full` that
70
+ * does not fit the language's lists; that error carries `keyPath`
71
+ * `["name", "full"]`.
72
+ */
73
+ export function generateNpc(spec: object, context: {
74
+ profile: object;
75
+ names: object;
76
+ language?: string | undefined;
77
+ seed?: string | undefined;
78
+ present?: unknown;
79
+ dateContext?: object | undefined;
80
+ defaults?: {
81
+ icon?: unknown;
82
+ species?: unknown;
83
+ packFolder?: unknown;
84
+ } | undefined;
85
+ taken?: ReadonlySet<string> | undefined;
86
+ }): {
87
+ frontmatter: object;
88
+ body: string;
89
+ text: string;
90
+ };
91
+ /**
92
+ * The canonical Address a `data.culture` value names, read as a culture
93
+ * reference is: a `lore` note in this package unless it says otherwise.
94
+ *
95
+ * @param {unknown} value - The value as written, or a decoded tuple.
96
+ * @param {object} index - The link index.
97
+ * @returns {string|undefined} The Address, or `undefined` where it reads as none.
98
+ */
99
+ export function cultureKey(value: unknown, index: object): string | undefined;
100
+ /**
101
+ * The commonest value of each of `icon`, `species` and `packFolder` among the
102
+ * package's npcs, as their notes write it: those of the same culture first,
103
+ * then any npc. A tie goes to the value that sorts first.
104
+ *
105
+ * @param {object} index - The link index.
106
+ * @param {string|undefined} culture - The culture's canonical Address.
107
+ * @returns {{icon?: unknown, species?: unknown, packFolder?: unknown, taken: Set<string>}}
108
+ * The defaults, and the shortcodes the package's beings hold.
109
+ */
110
+ export function npcDefaults(index: object, culture: string | undefined): {
111
+ icon?: unknown;
112
+ species?: unknown;
113
+ packFolder?: unknown;
114
+ taken: Set<string>;
115
+ };
116
+ /** The youngest and oldest age, in whole years, a generated person is born to. */
117
+ export const ADULT_AGE: Readonly<{
118
+ min: 18;
119
+ max: 60;
120
+ }>;
121
+ /** The longest shortcode the derivation makes. */
122
+ export const SHORTCODE_LENGTH: 12;
123
+ /** The spec fields `npc new` requires, as paths. */
124
+ export const REQUIRED_SPEC_FIELDS: readonly string[];
@@ -0,0 +1,164 @@
1
+ /**
2
+ * Every settlements table in a note, read from the raw file so each line
3
+ * number is the file's own.
4
+ *
5
+ * @param {string} raw - The whole note, frontmatter included.
6
+ * @returns {{heading: number, tables: SettlementTable[]}} The `## Settlements`
7
+ * heading's line, 0 when there is none, and its tables.
8
+ */
9
+ export function findSettlementTables(raw: string): {
10
+ heading: number;
11
+ tables: SettlementTable[];
12
+ };
13
+ /**
14
+ * Check a place note's settlements tables.
15
+ *
16
+ * Declared as part of the `place` vocabulary's whole-note check, so the lint
17
+ * runs it with the index every reference resolves through. Without an index
18
+ * nothing is reported.
19
+ *
20
+ * @param {object} note - The note, as the link index hands it over.
21
+ * @param {object} [opts]
22
+ * @param {object} [opts.index] - The link index, holding the whole corpus.
23
+ * @returns {object[]} Findings.
24
+ */
25
+ export function checkSettlementTables(note: object, { index }?: {
26
+ index?: object | undefined;
27
+ }): object[];
28
+ /** The heading text a settlements table stands under, at level two. */
29
+ export const SETTLEMENTS_HEADING: "Settlements";
30
+ /**
31
+ * How a region's countryside is held, each the tag a region carries to say so.
32
+ *
33
+ * `holder` is what the `Held by` cell names under that model. `person` says
34
+ * whether that holder may be a person: only where land is held by a person or
35
+ * a house may the cell link a `being`.
36
+ *
37
+ * **The tags stay open.** They are not a declared tag group: a group would
38
+ * report every tag within a typo's distance of one — a region tagged `hellad`
39
+ * reads as a near miss of `held` — and a misspelled model on a note with a
40
+ * table is already reported, because the note then names no model at all.
41
+ *
42
+ * @type {ReadonlyArray<Readonly<{tag: string, holder: string, person: boolean}>>}
43
+ */
44
+ export const HOLDING_MODELS: ReadonlyArray<Readonly<{
45
+ tag: string;
46
+ holder: string;
47
+ person: boolean;
48
+ }>>;
49
+ /**
50
+ * The table's columns, in the order the header states them. An optional
51
+ * column may be left out; the header carries no other column, and keeps this
52
+ * order.
53
+ *
54
+ * @type {ReadonlyArray<Readonly<{name: string, required: boolean}>>}
55
+ */
56
+ export const SETTLEMENT_COLUMNS: ReadonlyArray<Readonly<{
57
+ name: string;
58
+ required: boolean;
59
+ }>>;
60
+ /**
61
+ * The rules this module enforces, each `name` the prefix its findings carry.
62
+ *
63
+ * @type {ReadonlyArray<Readonly<{name: string, describe: string}>>}
64
+ */
65
+ export const SETTLEMENT_TABLE_RULES: ReadonlyArray<Readonly<{
66
+ name: string;
67
+ describe: string;
68
+ }>>;
69
+ /**
70
+ * One cell, as authored.
71
+ */
72
+ export type Cell = {
73
+ /**
74
+ * - The cell, trimmed.
75
+ */
76
+ text: string;
77
+ /**
78
+ * - The 1-based column its text starts at.
79
+ */
80
+ column: number;
81
+ };
82
+ /**
83
+ * One settlements table.
84
+ */
85
+ export type SettlementTable = {
86
+ /**
87
+ * - The 1-based line of its header.
88
+ */
89
+ line: number;
90
+ /**
91
+ * - The header cells.
92
+ */
93
+ header: string[];
94
+ /**
95
+ * - Whether the header is the declared columns.
96
+ */
97
+ wellFormed: boolean;
98
+ /**
99
+ * - Each
100
+ * row's cells keyed by column name; empty when the header is not well formed.
101
+ */
102
+ rows: Array<{
103
+ line: number;
104
+ cells: Record<string, Cell>;
105
+ }>;
106
+ /**
107
+ * - The 1-based line of its last row.
108
+ */
109
+ last: number;
110
+ /**
111
+ * - Whether prose follows it before the next heading.
112
+ */
113
+ tailed: boolean;
114
+ };
115
+ /**
116
+ * One place note, as the rules read it.
117
+ */
118
+ export type PlaceNode = {
119
+ /**
120
+ * - The note.
121
+ */
122
+ note: object;
123
+ /**
124
+ * - Lower case.
125
+ */
126
+ shortcode: string;
127
+ subType: string;
128
+ title: string;
129
+ /**
130
+ * - Its name and aliases, lower case.
131
+ */
132
+ names: Set<string>;
133
+ /**
134
+ * - Enclosing places' shortcodes.
135
+ */
136
+ parents: string[];
137
+ section: {
138
+ heading: number;
139
+ tables: SettlementTable[];
140
+ };
141
+ };
142
+ /**
143
+ * Everything the rules ask of the whole tree.
144
+ */
145
+ export type Corpus = {
146
+ /**
147
+ * - By shortcode.
148
+ */
149
+ places: Map<string, PlaceNode>;
150
+ /**
151
+ * - By note.
152
+ */
153
+ byNote: Map<object, PlaceNode>;
154
+ /**
155
+ * - Region shortcode → the
156
+ * settlement notes its table covers.
157
+ */
158
+ covers: Map<string, PlaceNode[]>;
159
+ /**
160
+ * - Settlement note → the region
161
+ * notes whose tables link it, in path order.
162
+ */
163
+ rowedIn: Map<object, object[]>;
164
+ };