@heroiclands/package-build 23.2.1 → 23.3.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 +25 -0
- package/ci/content-format-reference.mjs +28 -5
- package/content-config.mjs +15 -0
- package/docs/api.md +37 -23
- package/docs/authoring/frontmatter.md +2 -0
- package/docs/configuration.md +10 -0
- package/docs/content-format.md +4 -0
- package/docs/guides/book.md +10 -0
- package/docs/guides/e2e.md +8 -1
- package/docs/reference/format-details.md +260 -7
- package/docs/reference/note-types.md +27 -27
- package/e2e.mjs +37 -10
- package/engine/content-format.yaml +6 -0
- package/engine/data-keys.mjs +6 -2
- package/engine/index.mjs +3 -0
- package/engine/infobox.mjs +1 -1
- package/engine/note-vocabulary.mjs +209 -17
- package/engine/pdf-build.mjs +10 -9
- package/engine/pdf-index.mjs +15 -2
- package/engine/pdf-pages.mjs +29 -6
- package/engine/settlement-tables.mjs +777 -0
- package/hugo-theme/layouts/_default/baseof.html +1 -1
- package/package.json +1 -1
- package/types/e2e.d.mts +5 -1
- package/types/engine/index.d.mts +1 -0
- package/types/engine/infobox.d.mts +1 -1
- package/types/engine/note-vocabulary.d.mts +31 -0
- package/types/engine/pdf-index.d.mts +5 -1
- package/types/engine/pdf-pages.d.mts +20 -0
- package/types/engine/settlement-tables.d.mts +164 -0
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
enough — the system deliberately uses no Pro-only icons — and the
|
|
16
16
|
game-icons webfont is subset to just the glyphs the docs reference
|
|
17
17
|
(~3 KB), generated by the SoHL repo. */}}
|
|
18
|
-
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/7.
|
|
18
|
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/7.3.1/css/all.min.css" crossorigin="anonymous" referrerpolicy="no-referrer">
|
|
19
19
|
<link rel="stylesheet" href="{{ "css/sohl-icons.css" | relURL }}">
|
|
20
20
|
</head>
|
|
21
21
|
<body>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@heroiclands/package-build",
|
|
3
|
-
"version": "23.
|
|
3
|
+
"version": "23.3.0",
|
|
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>;
|
package/types/engine/index.d.mts
CHANGED
|
@@ -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: `
|
|
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.
|
|
@@ -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
|
*
|
|
@@ -17,6 +17,9 @@ export function indexMarker(slug: string, main?: boolean): string;
|
|
|
17
17
|
* @param {object} [opts] - Options.
|
|
18
18
|
* @param {(entry: object) => boolean} [opts.owns] - Whether this book is the
|
|
19
19
|
* entry's home. Every entry when absent.
|
|
20
|
+
* @param {string[]} [opts.heads] - Leading words (`pdf.indexHeads`) matched
|
|
21
|
+
* literally against the start of a name; a name that opens with one is also
|
|
22
|
+
* listed as `<rest>, <head>`, the head without its trailing space or colon. None when absent.
|
|
20
23
|
* @param {Array<{slug: string, name: string, title: string, page: string|number}>} [opts.foreign] -
|
|
21
24
|
* Notes another book prints, listed as `Name: Book title, p. N` once this
|
|
22
25
|
* book mentions them.
|
|
@@ -24,8 +27,9 @@ export function indexMarker(slug: string, main?: boolean): string;
|
|
|
24
27
|
* foreign?: {title: string, page: string}}>} Terms with `see` set for a
|
|
25
28
|
* cross-reference to the main name it points at.
|
|
26
29
|
*/
|
|
27
|
-
export function indexTerms(entries: object[], { owns, foreign }?: {
|
|
30
|
+
export function indexTerms(entries: object[], { owns, foreign, heads }?: {
|
|
28
31
|
owns?: ((entry: object) => boolean) | undefined;
|
|
32
|
+
heads?: string[] | undefined;
|
|
29
33
|
foreign?: {
|
|
30
34
|
slug: string;
|
|
31
35
|
name: string;
|
|
@@ -10,6 +10,26 @@
|
|
|
10
10
|
* @returns {string[]} The arguments, in order.
|
|
11
11
|
*/
|
|
12
12
|
export function evalArgs(typPath: string, fontArgs: string[]): string[];
|
|
13
|
+
/**
|
|
14
|
+
* Say why a finished Typst process failed.
|
|
15
|
+
*
|
|
16
|
+
* A process killed by a signal has no exit status and prints nothing, so the
|
|
17
|
+
* signal is named; `SIGKILL` is the kernel's out-of-memory kill. Otherwise the
|
|
18
|
+
* first line the compiler printed is the reason, and the exit code stands in
|
|
19
|
+
* when it printed none.
|
|
20
|
+
*
|
|
21
|
+
* @param {{status: number | null, signal: string | null, stderr?: string | null, stdout?: string | null}} result -
|
|
22
|
+
* The finished process.
|
|
23
|
+
* @param {string} binary - The Typst binary.
|
|
24
|
+
* @param {string} subcommand - The Typst subcommand that ran.
|
|
25
|
+
* @returns {string} The reason, ready to follow the failing command's name.
|
|
26
|
+
*/
|
|
27
|
+
export function typstFailure(result: {
|
|
28
|
+
status: number | null;
|
|
29
|
+
signal: string | null;
|
|
30
|
+
stderr?: string | null;
|
|
31
|
+
stdout?: string | null;
|
|
32
|
+
}, binary: string, subcommand: string): string;
|
|
13
33
|
/**
|
|
14
34
|
* Measure the page each labelled entry of a book starts on.
|
|
15
35
|
*
|
|
@@ -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
|
+
};
|