@heroiclands/package-build 25.5.5 → 25.6.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.
- package/CHANGELOG.md +18 -0
- package/assets/styles/content-base.css +1 -1
- package/docs/api.md +24 -16
- package/docs/authoring/frontmatter.md +1 -1
- package/docs/authoring/links-and-markup.md +10 -9
- package/docs/content-format.md +40 -1
- package/docs/diagnostics.md +2 -2
- package/docs/guides/reference-pages.md +4 -1
- package/docs/guides/site.md +1 -1
- package/docs/reference/format-details.md +174 -129
- package/docs/reference/note-types.md +134 -121
- package/docs/reference/theme-pages.md +1 -0
- package/engine/content-format.yaml +9 -7
- package/engine/content-html.mjs +3 -2
- package/engine/content-index.mjs +23 -0
- package/engine/content-links.mjs +8 -0
- package/engine/content-render.mjs +2 -2
- package/engine/content-tables.mjs +12 -5
- package/engine/culture-reach.mjs +3 -0
- package/engine/declared-sections.mjs +100 -0
- package/engine/derived-sections.mjs +36 -2
- package/engine/dictionary-rows.mjs +2 -1
- package/engine/generated-sections.mjs +2 -0
- package/engine/holdings.mjs +107 -3
- package/engine/index-records.mjs +3 -1
- package/engine/index.mjs +1 -1
- package/engine/language-data.mjs +0 -1
- package/engine/language-rows.mjs +1 -3
- package/engine/language-terms.mjs +7 -10
- package/engine/map-dot.mjs +22 -0
- package/engine/markdown-blocks.mjs +23 -8
- package/engine/metadata-index.mjs +1 -0
- package/engine/note-addresses.mjs +16 -0
- package/engine/note-vocabulary.mjs +19 -8
- package/engine/office-holders.mjs +76 -0
- package/engine/page-breaks.mjs +36 -8
- package/engine/pdf-render.mjs +4 -3
- package/engine/place-kinds.mjs +106 -0
- package/engine/settlement-tables.mjs +410 -675
- package/engine/settlement-terms.mjs +118 -0
- package/engine/site-build.mjs +2 -4
- package/engine/sql-tables.mjs +101 -7
- package/engine/standing-terms.mjs +9 -5
- package/engine/standings.mjs +83 -31
- package/engine/unique-items.mjs +85 -0
- package/package.json +9 -4
- package/site-theme/data/banner-kinds.yaml +2 -0
- package/sohl/actors.mjs +4 -3
- package/types/engine/content-html.d.mts +2 -1
- package/types/engine/culture-reach.d.mts +3 -0
- package/types/engine/declared-sections.d.mts +30 -0
- package/types/engine/derived-sections.d.mts +5 -1
- package/types/engine/holdings.d.mts +34 -2
- package/types/engine/index-records.d.mts +2 -1
- package/types/engine/language-terms.d.mts +5 -1
- package/types/engine/markdown-blocks.d.mts +5 -1
- package/types/engine/office-holders.d.mts +33 -0
- package/types/engine/page-breaks.d.mts +8 -0
- package/types/engine/place-kinds.d.mts +18 -0
- package/types/engine/settlement-tables.d.mts +25 -158
- package/types/engine/settlement-terms.d.mts +53 -0
- package/types/engine/sql-tables.d.mts +35 -3
- package/types/engine/standing-terms.d.mts +3 -2
- package/types/engine/standings.d.mts +14 -2
- package/types/engine/unique-items.d.mts +12 -0
- package/vendor/markdownlint.mjs +855 -569
package/sohl/actors.mjs
CHANGED
|
@@ -42,7 +42,8 @@
|
|
|
42
42
|
* **A membership is derived, never authored here.** `data.affiliations` names
|
|
43
43
|
* the bodies a being belongs to and the standing it holds in each, and each
|
|
44
44
|
* entry becomes one embedded affiliation item: the entry's `rank` is that
|
|
45
|
-
* item's `system.level`, its `office` is `system.office
|
|
45
|
+
* item's `system.level`, its `office` is `system.office` (several posts joined
|
|
46
|
+
* by commas), and the first of its
|
|
46
47
|
* `societies` is `system.society`, the one society the SoHL item carries. A
|
|
47
48
|
* standing is a fact about the setting rather than about one system — it does
|
|
48
49
|
* not become true because SoHL is installed — so the system block states none
|
|
@@ -76,7 +77,7 @@ import { blockProperty, mergeSystemData } from "../engine/system-block.mjs";
|
|
|
76
77
|
// A being's memberships and the standing it holds in each, read from the one
|
|
77
78
|
// place they are authored. The rank *is* the affiliation item's `level`, so
|
|
78
79
|
// there is nothing to map and nowhere for a second authoring to disagree.
|
|
79
|
-
import { readStandings } from "../engine/standings.mjs";
|
|
80
|
+
import { readStandings, standingOffices } from "../engine/standings.mjs";
|
|
80
81
|
|
|
81
82
|
/**
|
|
82
83
|
* The system this pass compiles for — the block its notes write.
|
|
@@ -234,7 +235,7 @@ export class Actors extends SystemActorCompiler {
|
|
|
234
235
|
const shortcode = body?.shortcode;
|
|
235
236
|
if (!shortcode) continue;
|
|
236
237
|
const level = Number(standing?.rank);
|
|
237
|
-
const office =
|
|
238
|
+
const office = standingOffices(standing).join(", ");
|
|
238
239
|
const [first] = Array.isArray(standing?.societies) ? standing.societies : [];
|
|
239
240
|
const society = typeof first === "string" ? first.trim() : "";
|
|
240
241
|
const system = {
|
|
@@ -74,7 +74,8 @@ export function lintContentHtml(contentBase: string, { skipDirectories, sources
|
|
|
74
74
|
* markdown's own angle brackets out of it: an autolink is `<https://…>`, and
|
|
75
75
|
* `https` is followed by `:` rather than whitespace or `>`, so the pattern
|
|
76
76
|
* stops. A comparison written in prose — `a < b` — has no name after the
|
|
77
|
-
* bracket at all.
|
|
77
|
+
* bracket at all. A doubled `<<` opens a quotation, so its second bracket
|
|
78
|
+
* never starts an HTML tag.
|
|
78
79
|
*
|
|
79
80
|
* Attributes are consumed as "anything but a bracket", deliberately loosely: a
|
|
80
81
|
* finding names the tag, and a pattern that tried to parse attribute syntax
|
|
@@ -42,6 +42,9 @@ export function noteTerms(index: object, note: object, entry?: object): Map<stri
|
|
|
42
42
|
* in a tree that describes peoples. Its ranks and offices then have no
|
|
43
43
|
* culture associations for term queries.
|
|
44
44
|
*
|
|
45
|
+
* The note's `data.culture` is the culture the content index resolved for it:
|
|
46
|
+
* its own, else the one its `data.parents` chain agrees on.
|
|
47
|
+
*
|
|
45
48
|
* @param {object} note - An `affiliation` note.
|
|
46
49
|
* @param {{index?: object}} [context]
|
|
47
50
|
* @returns {object[]} One warning, at the note's `type`, or none.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/** Authored headings, excluding literal examples and named containers. */
|
|
2
|
+
export function declaredHeadings(markdown: any, syntax: any): {
|
|
3
|
+
level: number;
|
|
4
|
+
line: number;
|
|
5
|
+
text: string;
|
|
6
|
+
id: string;
|
|
7
|
+
classes: string[];
|
|
8
|
+
values: Record<string, string>;
|
|
9
|
+
}[];
|
|
10
|
+
/**
|
|
11
|
+
* Insert indexed content at its heading while preserving subsequent source lines.
|
|
12
|
+
* @param {string} markdown - Expanded body.
|
|
13
|
+
* @param {Array<{slug:string,heading:string,markdown:string}>} [sections] - Declared content.
|
|
14
|
+
* @param {{authored?:string,lineMap?:object[],generatedFrom?:number,syntax?:Function}} [context] - Captured source mappings.
|
|
15
|
+
* @returns {{markdown:string,lineMap:object[],generatedFrom?:number}} Expanded body and locations.
|
|
16
|
+
*/
|
|
17
|
+
export function insertDeclaredSections(markdown: string, sections?: Array<{
|
|
18
|
+
slug: string;
|
|
19
|
+
heading: string;
|
|
20
|
+
markdown: string;
|
|
21
|
+
}>, { authored, lineMap, generatedFrom, syntax }?: {
|
|
22
|
+
authored?: string;
|
|
23
|
+
lineMap?: object[];
|
|
24
|
+
generatedFrom?: number;
|
|
25
|
+
syntax?: Function;
|
|
26
|
+
}): {
|
|
27
|
+
markdown: string;
|
|
28
|
+
lineMap: object[];
|
|
29
|
+
generatedFrom?: number;
|
|
30
|
+
};
|
|
@@ -51,15 +51,19 @@ export function drawMapsFrom(records: object[], { outDir, foreignIndex, config,
|
|
|
51
51
|
* prepared results are keyed.
|
|
52
52
|
* @param {Map<string, object>} [opts.foreignIndex] - The fetched indexes.
|
|
53
53
|
* @param {object} [opts.config] - The resolved configuration.
|
|
54
|
+
* @param {(file:string)=>string|undefined} [opts.rawOf] - Captured source locators.
|
|
55
|
+
* @param {object[]} [opts.all=records] - Complete records for settlement validation.
|
|
54
56
|
* @param {string} [opts.only] - One note file to give sections to; absent,
|
|
55
57
|
* every note.
|
|
56
58
|
* @returns {Map<string, Map<string, string>>} Note file to its sections, each
|
|
57
59
|
* keyed by its slug, for every note given at least one.
|
|
58
60
|
*/
|
|
59
|
-
export function derivedSections(records: object[], { fileOf, foreignIndex, config, only }: {
|
|
61
|
+
export function derivedSections(records: object[], { fileOf, foreignIndex, config, only, rawOf, all }: {
|
|
60
62
|
fileOf: (record: object) => string;
|
|
61
63
|
foreignIndex?: Map<string, object> | undefined;
|
|
62
64
|
config?: object | undefined;
|
|
65
|
+
rawOf?: ((file: string) => string | undefined) | undefined;
|
|
66
|
+
all?: object[] | undefined;
|
|
63
67
|
only?: string | undefined;
|
|
64
68
|
}): Map<string, Map<string, string>>;
|
|
65
69
|
/**
|
|
@@ -47,13 +47,45 @@ export function foreignHoldingsNodes(foreignIndex: Map<string, object> | undefin
|
|
|
47
47
|
export function holdingsPages(nodes: Iterable<HoldingsNode | null>, { governmentNodes }?: {
|
|
48
48
|
governmentNodes?: Iterable<HoldingsNode | null> | undefined;
|
|
49
49
|
}): Map<string, Holdings>;
|
|
50
|
+
/**
|
|
51
|
+
* Whether a record's `data.government` came from a parent rather than its own
|
|
52
|
+
* note.
|
|
53
|
+
*
|
|
54
|
+
* @param {object} record - An index record.
|
|
55
|
+
* @returns {boolean} True for a district that inherited its government.
|
|
56
|
+
*/
|
|
57
|
+
export function governmentInherited(record: object): boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Give each district that states no government its parent's.
|
|
60
|
+
*
|
|
61
|
+
* A `place/district` falls under the government of the place it stands
|
|
62
|
+
* within. One stating no `data.government` key takes the value of its nearest
|
|
63
|
+
* parent that states the key, walking `data.parents` breadth first, in the
|
|
64
|
+
* order written, through any parent that states none, and never visiting a
|
|
65
|
+
* place twice. An explicit value on the district, `null` (complete anarchy)
|
|
66
|
+
* included, is its own and is kept; a parent's explicit `null` is inherited as
|
|
67
|
+
* anarchy. Every reader of the index — the Governed by and Governed places
|
|
68
|
+
* sections, the "missing government" advisory, a consumer of the published
|
|
69
|
+
* index — then reads the effective government at `data.government`.
|
|
70
|
+
*
|
|
71
|
+
* @param {object[]} records - Content-index records, edited in place.
|
|
72
|
+
* @param {object} [opts]
|
|
73
|
+
* @param {(key: string) => object|undefined} [opts.foreignRecord] - A fetched
|
|
74
|
+
* index's record by canonical Address, for a parent in a dependency.
|
|
75
|
+
* @returns {void}
|
|
76
|
+
*/
|
|
77
|
+
export function inheritDistrictGovernments(records: object[], { foreignRecord }?: {
|
|
78
|
+
foreignRecord?: ((key: string) => object | undefined) | undefined;
|
|
79
|
+
}): void;
|
|
50
80
|
/**
|
|
51
81
|
* Advise when a place with an authored positive population omits government.
|
|
52
82
|
* Missing, null or zero population establishes no inhabited population.
|
|
53
83
|
* Property presence distinguishes omitted government from explicit null,
|
|
54
84
|
* which means complete anarchy. Non-null values are validated by the declared
|
|
55
|
-
* affiliation reference field.
|
|
56
|
-
* supplies
|
|
85
|
+
* affiliation reference field. Tenure never supplies this fact, and
|
|
86
|
+
* containment supplies it only to a district, which the content index gives
|
|
87
|
+
* its nearest parent's government (see {@link inheritDistrictGovernments}), so
|
|
88
|
+
* a district under a governed place is never advised.
|
|
57
89
|
*
|
|
58
90
|
* @param {object} note - The note with parsed frontmatter and raw source.
|
|
59
91
|
* @returns {object[]} Located warning findings.
|
|
@@ -122,7 +122,8 @@ export function recordPath(record: Record<string, any>): string;
|
|
|
122
122
|
* since a note declaring its own is a hard error — and it matches what
|
|
123
123
|
* the content-table expander puts on the same field, so a query reads the same
|
|
124
124
|
* value from either. `file` namespaces the note's place in the tree, again
|
|
125
|
-
* matching the expander's `file.*`.
|
|
125
|
+
* matching the expander's `file.*`. `officeHolders` lists, on a body, the
|
|
126
|
+
* living beings whose own standing names each of its offices.
|
|
126
127
|
*
|
|
127
128
|
* Both are checked rather than assumed: `folder` is real frontmatter on most
|
|
128
129
|
* notes, so the neighbouring names are close enough to a real key that a silent
|
|
@@ -94,7 +94,11 @@ export const JOIN_MEETINGS: readonly string[];
|
|
|
94
94
|
* letters between, `drop` loses the first, `double` doubles the consonant.
|
|
95
95
|
*/
|
|
96
96
|
export const JOIN_RULES: readonly string[];
|
|
97
|
-
/**
|
|
97
|
+
/**
|
|
98
|
+
* What a written mark says of its letter: `stress` falls on it, `length` holds
|
|
99
|
+
* it longer, `apart` says it apart from its neighbour, and `quality` changes
|
|
100
|
+
* which vowel is said.
|
|
101
|
+
*/
|
|
98
102
|
export const MARK_KINDS: readonly string[];
|
|
99
103
|
/** How many of a mark a word may carry: `one` at most, or `any` number. */
|
|
100
104
|
export const MARK_LIMITS: readonly string[];
|
|
@@ -3,6 +3,10 @@
|
|
|
3
3
|
* and must not be modified; an `inline` token carries no `children`.
|
|
4
4
|
*
|
|
5
5
|
* @param {unknown} source - Markdown.
|
|
6
|
+
* @param {object} [options] - Optional block projection.
|
|
7
|
+
* @param {boolean} [options.footnotes=false] - Include footnote definition containers.
|
|
6
8
|
* @returns {readonly import("markdown-it").Token[]} The block tokens, in order.
|
|
7
9
|
*/
|
|
8
|
-
export function blockTokens(source: unknown
|
|
10
|
+
export function blockTokens(source: unknown, { footnotes }?: {
|
|
11
|
+
footnotes?: boolean | undefined;
|
|
12
|
+
}): readonly import("markdown-it").Token[];
|
|
@@ -1,3 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A note's identity across its systems: `package-type-shortcode`, lowercased.
|
|
3
|
+
*
|
|
4
|
+
* A body's Item and its journal carry one page, and a being names the body by
|
|
5
|
+
* its `note` Address, so the system is left out.
|
|
6
|
+
*
|
|
7
|
+
* @param {{package?: string, type?: string, shortcode?: string}} tuple
|
|
8
|
+
* @returns {string} The key, or `""` where a part is missing.
|
|
9
|
+
*/
|
|
10
|
+
export function officeBodyKey(tuple: {
|
|
11
|
+
package?: string;
|
|
12
|
+
type?: string;
|
|
13
|
+
shortcode?: string;
|
|
14
|
+
}): string;
|
|
15
|
+
/**
|
|
16
|
+
* Each body's offices with the living beings that hold them.
|
|
17
|
+
*
|
|
18
|
+
* Nothing is authored on the office for this: a being states the post it holds
|
|
19
|
+
* in its own `data.affiliations.<body>.office`, and this collects, for every
|
|
20
|
+
* office in a body's `governance.offices`, each being naming it. A being whose
|
|
21
|
+
* `data.died` is set holds nothing, so a former holder drops out and a vacant
|
|
22
|
+
* office lists no one. A post the body does not declare is the standing check's
|
|
23
|
+
* finding and is listed nowhere.
|
|
24
|
+
*
|
|
25
|
+
* Offices keep the body's declared order; holders are ordered by name.
|
|
26
|
+
*
|
|
27
|
+
* @param {object[]} records - Content-index records; only note records are
|
|
28
|
+
* read.
|
|
29
|
+
* @returns {Map<string, Map<string, object[]>>} Body identity
|
|
30
|
+
* (`package-type-shortcode`) → office → the holding beings' records, for every
|
|
31
|
+
* body with at least one held office.
|
|
32
|
+
*/
|
|
33
|
+
export function officeHolders(records: object[]): Map<string, Map<string, object[]>>;
|
|
1
34
|
/**
|
|
2
35
|
* Validate one affiliation's office roster against dated beings in the corpus.
|
|
3
36
|
* @param {object} note
|
|
@@ -22,6 +22,14 @@ export function scanPageBreaks(source: string): {
|
|
|
22
22
|
* @returns {string} Markdown without valid page-break lines.
|
|
23
23
|
*/
|
|
24
24
|
export function omitPageBreaks(source: string): string;
|
|
25
|
+
/**
|
|
26
|
+
* Preserve refused markers as literal Markdown before the book slices blocks.
|
|
27
|
+
* A slice must not make a marker eligible by discarding its original neighbour.
|
|
28
|
+
* Findings are collected from the original source before this rewrite.
|
|
29
|
+
* @param {string} source - Complete Markdown body, before splitting containers.
|
|
30
|
+
* @returns {string} Markdown with invalid markers escaped for literal rendering.
|
|
31
|
+
*/
|
|
32
|
+
export function escapeInvalidPageBreaks(source: string): string;
|
|
25
33
|
/**
|
|
26
34
|
* Produce the book's page-break token, leaving ordinary thematic breaks alone.
|
|
27
35
|
* @param {import("markdown-it")} md - The book parser.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Check a district's parent and a route's journeys.
|
|
3
|
+
*
|
|
4
|
+
* A district naming no parent is reported at its `subType`; one whose parents
|
|
5
|
+
* all resolve and none is a settlement or a region is reported at `parents`.
|
|
6
|
+
* A parent that does not resolve is the Address check's finding, so a district
|
|
7
|
+
* whose only parents are unresolved earns nothing more here. A route stating no
|
|
8
|
+
* `data.routes` entry is reported at its `subType`.
|
|
9
|
+
*
|
|
10
|
+
* @param {object} note - The note: `file`, `raw` and parsed `fm`.
|
|
11
|
+
* @param {{index?: object}} [options] - The lint's options.
|
|
12
|
+
* @returns {object[]} Located findings.
|
|
13
|
+
*/
|
|
14
|
+
export function checkPlaceKind(note: object, { index }?: {
|
|
15
|
+
index?: object;
|
|
16
|
+
}): object[];
|
|
17
|
+
/** The place kinds a district may stand within. */
|
|
18
|
+
export const DISTRICT_PARENT_KINDS: readonly string[];
|
|
@@ -1,164 +1,31 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* @param {
|
|
6
|
-
* @returns {
|
|
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.
|
|
2
|
+
* Check indexed rows, locating each finding in its original YAML.
|
|
3
|
+
* @param {object} note - Indexed note and original locator text.
|
|
4
|
+
* @param {object} [opts] - Captured context.
|
|
5
|
+
* @param {object} [opts.index] - Complete local and dependency reference index.
|
|
6
|
+
* @returns {object[]} Located findings.
|
|
24
7
|
*/
|
|
25
8
|
export function checkSettlementTables(note: object, { index }?: {
|
|
26
9
|
index?: object | undefined;
|
|
27
10
|
}): 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
11
|
/**
|
|
70
|
-
*
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
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 listed forms, 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
|
-
};
|
|
12
|
+
* Fail every publishing surface before it writes invalid settlement output.
|
|
13
|
+
* @param {object[]} records - Indexed records, including documentation projections.
|
|
14
|
+
* @param {object} opts - Captured context.
|
|
15
|
+
* @param {(record: object) => string} opts.fileOf - Source filename for a record.
|
|
16
|
+
* @param {Map<string,object>} [opts.foreignIndex] - Dependency reference targets.
|
|
17
|
+
* @param {(file: string) => string|undefined} [opts.rawOf] - Captured locator text.
|
|
18
|
+
* @returns {void}
|
|
19
|
+
*/
|
|
20
|
+
export function assertSettlementRecords(records: object[], { fileOf, foreignIndex, rawOf }?: {
|
|
21
|
+
fileOf: (record: object) => string;
|
|
22
|
+
foreignIndex?: Map<string, object> | undefined;
|
|
23
|
+
rawOf?: ((file: string) => string | undefined) | undefined;
|
|
24
|
+
}): void;
|
|
25
|
+
/**
|
|
26
|
+
* Render rows once as shared Markdown; all surfaces consume the same table.
|
|
27
|
+
* @param {object} record - Indexed region.
|
|
28
|
+
* @returns {string} Generated table and its closing sentence.
|
|
29
|
+
*/
|
|
30
|
+
export function settlementMarkdown(record: object): string;
|
|
31
|
+
export { SETTLEMENTS_HEADING, SETTLEMENT_COLUMNS, SETTLEMENT_ROW_FIELDS, SETTLEMENTS_FIELD, SETTLEMENT_TABLE_RULES } from "./settlement-terms.mjs";
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/** Dependency-free settlement row declarations. @module */
|
|
2
|
+
/** The generated heading. */
|
|
3
|
+
export const SETTLEMENTS_HEADING: "Settlements";
|
|
4
|
+
/** Rendered columns, in their fixed order; Held by and For appear when a row states them. */
|
|
5
|
+
export const SETTLEMENT_COLUMNS: readonly (Readonly<{
|
|
6
|
+
name: "Name";
|
|
7
|
+
required: true;
|
|
8
|
+
}> | Readonly<{
|
|
9
|
+
name: "Market";
|
|
10
|
+
required: true;
|
|
11
|
+
}> | Readonly<{
|
|
12
|
+
name: "People";
|
|
13
|
+
required: true;
|
|
14
|
+
}> | Readonly<{
|
|
15
|
+
name: "Held by";
|
|
16
|
+
required: false;
|
|
17
|
+
}> | Readonly<{
|
|
18
|
+
name: "For";
|
|
19
|
+
required: false;
|
|
20
|
+
}>)[];
|
|
21
|
+
/** The closed row fields; existing subjects use native Addresses. */
|
|
22
|
+
export const SETTLEMENT_ROW_FIELDS: readonly Readonly<unknown>[];
|
|
23
|
+
/** The place vocabulary's single settlement declaration. */
|
|
24
|
+
export const SETTLEMENTS_FIELD: Readonly<{
|
|
25
|
+
name: "settlements";
|
|
26
|
+
kind: "map";
|
|
27
|
+
shape: "{ rows, tail }";
|
|
28
|
+
fields: readonly ({
|
|
29
|
+
name: string;
|
|
30
|
+
kind: string;
|
|
31
|
+
required: boolean;
|
|
32
|
+
shape: string;
|
|
33
|
+
entries: {
|
|
34
|
+
kind: string;
|
|
35
|
+
shape: string;
|
|
36
|
+
fields: readonly Readonly<unknown>[];
|
|
37
|
+
};
|
|
38
|
+
describe: string;
|
|
39
|
+
} | {
|
|
40
|
+
name: string;
|
|
41
|
+
kind: string;
|
|
42
|
+
required: boolean;
|
|
43
|
+
shape: string;
|
|
44
|
+
describe: string;
|
|
45
|
+
entries?: undefined;
|
|
46
|
+
})[];
|
|
47
|
+
describe: "A region's settlement rows and the sentence stating what they leave out; the table is generated from this declaration.";
|
|
48
|
+
}>;
|
|
49
|
+
/** Every semantic finding, named once for the reference and its guards. */
|
|
50
|
+
export const SETTLEMENT_TABLE_RULES: readonly Readonly<{
|
|
51
|
+
name: string;
|
|
52
|
+
describe: string;
|
|
53
|
+
}>[];
|
|
@@ -21,6 +21,23 @@ export function findSqlBlocks(markdown: string): Array<{
|
|
|
21
21
|
layout: string;
|
|
22
22
|
block: string;
|
|
23
23
|
}>;
|
|
24
|
+
/**
|
|
25
|
+
* Where a query reads the `file` block of the index record: `file.path`,
|
|
26
|
+
* `file.folder` or `file.name`, bare or qualified by a relation or its alias.
|
|
27
|
+
* A note is selected by property, tag or address, so a query that reaches for
|
|
28
|
+
* the file it was written in is refused. A field of a note's own data that is
|
|
29
|
+
* named `file` is not the block and is left alone.
|
|
30
|
+
*
|
|
31
|
+
* @param {string} sql - One fence's query.
|
|
32
|
+
* @returns {{line: number, column: number, text: string}|undefined} The first
|
|
33
|
+
* reference, its 0-based line within the query and 1-based column, or
|
|
34
|
+
* nothing where the query makes none.
|
|
35
|
+
*/
|
|
36
|
+
export function findFileReference(sql: string): {
|
|
37
|
+
line: number;
|
|
38
|
+
column: number;
|
|
39
|
+
text: string;
|
|
40
|
+
} | undefined;
|
|
24
41
|
/**
|
|
25
42
|
* Open a DuckDB view over the content index.
|
|
26
43
|
*
|
|
@@ -205,25 +222,35 @@ export function prepareInlineSqlExpressions(db: any, sources: any): Promise<Map<
|
|
|
205
222
|
* @param {Map<string, Map<string, string>>} [opts.derived] - The derived
|
|
206
223
|
* lists, from an earlier call over the same records, which are not derived
|
|
207
224
|
* again.
|
|
225
|
+
* @param {Map<string,{raw?:string}>} [opts.parsed] - Captured source locators.
|
|
208
226
|
* @param {object[]} [opts.all=records] - Complete records for lexical lineage
|
|
209
227
|
* traversal through providers outside the surface's audience.
|
|
210
228
|
* @returns {Promise<{sections: Map<string, string>, views: Set<string>,
|
|
211
229
|
* derived: Map<string, Map<string, string>>,
|
|
212
|
-
* lexical: Map<string, import("./lexical-sections.mjs").LexicalSection[]
|
|
230
|
+
* lexical: Map<string, import("./lexical-sections.mjs").LexicalSection[]>,
|
|
231
|
+
* declared: Map<string, Array<{slug:string,heading:string,markdown:string}>>}>} Note file to its sections,
|
|
213
232
|
* joined in order; the files whose sections hold an event view's fence; and
|
|
214
233
|
* the derived lists alone.
|
|
215
234
|
*/
|
|
216
|
-
export function generatedSectionsFor(db: object | undefined, records: object[], contentBase: string, { only, foreignIndex, config, derived: given, all }?: {
|
|
235
|
+
export function generatedSectionsFor(db: object | undefined, records: object[], contentBase: string, { only, foreignIndex, config, derived: given, all, parsed }?: {
|
|
217
236
|
only?: string | undefined;
|
|
218
237
|
foreignIndex?: Map<string, object> | undefined;
|
|
219
238
|
config?: object | undefined;
|
|
220
239
|
derived?: Map<string, Map<string, string>> | undefined;
|
|
240
|
+
parsed?: Map<string, {
|
|
241
|
+
raw?: string;
|
|
242
|
+
}> | undefined;
|
|
221
243
|
all?: object[] | undefined;
|
|
222
244
|
}): Promise<{
|
|
223
245
|
sections: Map<string, string>;
|
|
224
246
|
views: Set<string>;
|
|
225
247
|
derived: Map<string, Map<string, string>>;
|
|
226
248
|
lexical: Map<string, import("./lexical-sections.mjs").LexicalSection[]>;
|
|
249
|
+
declared: Map<string, Array<{
|
|
250
|
+
slug: string;
|
|
251
|
+
heading: string;
|
|
252
|
+
markdown: string;
|
|
253
|
+
}>>;
|
|
227
254
|
}>;
|
|
228
255
|
/**
|
|
229
256
|
* Join each note's generated sections to its body among the sources a
|
|
@@ -262,13 +289,18 @@ export function joinGeneratedSections(generated: {
|
|
|
262
289
|
* empty set carrying them.
|
|
263
290
|
*
|
|
264
291
|
* @param {Map<string, object[]>} prepared - From {@link prepareSqlTables}.
|
|
265
|
-
* @param {{sections: Map<string, string>, lexical?: Map<string, import("./lexical-sections.mjs").LexicalSection[]
|
|
292
|
+
* @param {{sections: Map<string, string>, lexical?: Map<string, import("./lexical-sections.mjs").LexicalSection[]>, declared?: Map<string, Array<{slug:string,heading:string,markdown:string}>>}} generated - From
|
|
266
293
|
* {@link generatedSectionsFor}.
|
|
267
294
|
* @returns {void}
|
|
268
295
|
*/
|
|
269
296
|
export function attachGeneratedSections(prepared: Map<string, object[]>, generated: {
|
|
270
297
|
sections: Map<string, string>;
|
|
271
298
|
lexical?: Map<string, import("./lexical-sections.mjs").LexicalSection[]>;
|
|
299
|
+
declared?: Map<string, Array<{
|
|
300
|
+
slug: string;
|
|
301
|
+
heading: string;
|
|
302
|
+
markdown: string;
|
|
303
|
+
}>>;
|
|
272
304
|
}): void;
|
|
273
305
|
/**
|
|
274
306
|
* Each declared dependency's cached index, as {@link openNotesDatabase} attaches
|
|
@@ -20,8 +20,9 @@ export const STANDING_BODY_TYPES: readonly string[];
|
|
|
20
20
|
* The keys one standing carries, as inner-key declarations.
|
|
21
21
|
*
|
|
22
22
|
* `rank` is the level on the body's own `governance.ranks` ladder, and every
|
|
23
|
-
* membership states one. `office` is a key of its `governance.offices` map,
|
|
24
|
-
*
|
|
23
|
+
* membership states one. `office` is a key of its `governance.offices` map, or
|
|
24
|
+
* a list of them where the being holds several posts in that body, and is
|
|
25
|
+
* stated only where the being holds a post. `societies` names the societies
|
|
25
26
|
* the membership is held in, as a list because a membership can span several.
|
|
26
27
|
*
|
|
27
28
|
* @type {readonly import("./data-keys.mjs").InnerKeySpec[]}
|
|
@@ -98,12 +98,24 @@ export function standingsDigest(fm: object): {
|
|
|
98
98
|
ranks?: Record<string, string>;
|
|
99
99
|
offices?: Record<string, string>;
|
|
100
100
|
} | undefined;
|
|
101
|
+
/**
|
|
102
|
+
* The posts a standing holds, trimmed, in the order written.
|
|
103
|
+
*
|
|
104
|
+
* `office` is one post or a list of them, and every reader — the line on the
|
|
105
|
+
* being's page, the SoHL item, the derived holders of an office — wants the
|
|
106
|
+
* same list from both.
|
|
107
|
+
*
|
|
108
|
+
* @param {object} [standing] - `{rank, office}`, either or both absent.
|
|
109
|
+
* @returns {string[]} The posts, blank and non-text entries left out.
|
|
110
|
+
*/
|
|
111
|
+
export function standingOffices(standing?: object): string[];
|
|
101
112
|
/**
|
|
102
113
|
* What a standing says before the body that confers it — `War Chief, Hárár
|
|
103
114
|
* (5), of ` — or `""` where no standing is held.
|
|
104
115
|
*
|
|
105
116
|
* The office leads, because it is the more particular of the two: a reader
|
|
106
|
-
* meeting "War Chief" has been told the rung as well.
|
|
117
|
+
* meeting "War Chief" has been told the rung as well. Several posts in one
|
|
118
|
+
* body lead in the order written, `Treasurer, Chancellor, …`. The rung follows as its
|
|
107
119
|
* title with its level in parentheses, read from the body's own ladder; where
|
|
108
120
|
* the ladder names no rung at that level, or none is available, it reads as
|
|
109
121
|
* `Rank 5` and the number is not repeated. The body closes the phrase, which is
|
|
@@ -131,7 +143,7 @@ export function standingLead(standing: object, digest?: {
|
|
|
131
143
|
* 3. the entry states a standing at all — what a stated standing holds is the
|
|
132
144
|
* inner-key check's, read from {@link STANDING_FIELDS};
|
|
133
145
|
* 4. a `rank` is a level the named body's `governance.ranks` declares;
|
|
134
|
-
* 5. an `office` is a key of that body's `governance.offices`.
|
|
146
|
+
* 5. each post an `office` names is a key of that body's `governance.offices`.
|
|
135
147
|
*
|
|
136
148
|
* Both of the last two are read from the named body's own frontmatter as the
|
|
137
149
|
* lint runs, so a rung or a post that does not exist fails on every being pointing
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Report a unique item whose note links no place or being.
|
|
3
|
+
*
|
|
4
|
+
* @param {object} note - The note: `file`, `raw`, `body` and parsed `fm`.
|
|
5
|
+
* @param {{index?: object}} [options] - The lint's options.
|
|
6
|
+
* @returns {object[]} The finding, located at `unique`, or none.
|
|
7
|
+
*/
|
|
8
|
+
export function checkUniqueItem(note: object, { index }?: {
|
|
9
|
+
index?: object;
|
|
10
|
+
}): object[];
|
|
11
|
+
/** The note types a unique item's links must reach at least one of. */
|
|
12
|
+
export const UNIQUE_ITEM_LINK_TYPES: readonly string[];
|