@heroiclands/package-build 22.22.0 → 22.23.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 +32 -0
- package/bin/content-commands.mjs +51 -14
- package/ci/content-format-reference.mjs +1 -1
- package/content-config.mjs +80 -2
- package/docs/api.md +85 -72
- package/docs/authoring/assets.md +14 -0
- package/docs/authoring/dates-and-calendars.md +37 -1
- package/docs/authoring/links-and-markup.md +112 -31
- package/docs/commands.md +12 -10
- package/docs/configuration.md +90 -13
- package/docs/content-format.md +1 -1
- package/docs/guides/book.md +5 -4
- package/docs/reference/format-details.md +323 -60
- package/docs/reference/note-types.md +9 -9
- package/engine/anchors.mjs +16 -10
- package/engine/art-fields.mjs +118 -0
- package/engine/art-slots.mjs +7 -1
- package/engine/asset-index.mjs +160 -10
- package/engine/asset-replacement.mjs +93 -0
- package/engine/asset-types.mjs +240 -0
- package/engine/base-compiler.mjs +54 -2
- package/engine/bundles.mjs +13 -1
- package/engine/content-blocks.mjs +4 -4
- package/engine/content-embeds.mjs +19 -0
- package/engine/content-figures.mjs +468 -0
- package/engine/content-footnotes.mjs +10 -2
- package/engine/content-format.yaml +1 -1
- package/engine/content-images.mjs +126 -25
- package/engine/content-index.mjs +36 -10
- package/engine/field-reference.mjs +31 -10
- package/engine/field-spec.mjs +10 -8
- package/engine/foreign-catalog.mjs +143 -18
- package/engine/frontmatter-lint.mjs +73 -1
- package/engine/heading-attributes.mjs +31 -18
- package/engine/helpers.mjs +97 -30
- package/engine/infobox-registry.mjs +4 -1
- package/engine/infobox.mjs +47 -8
- package/engine/itinerary-scenes.mjs +4 -10
- package/engine/journals.mjs +264 -39
- package/engine/lore-events.mjs +197 -0
- package/engine/markdown-expressions.mjs +257 -7
- package/engine/note-dates.mjs +305 -12
- package/engine/note-vocabulary.mjs +11 -5
- package/engine/pathnames.mjs +36 -0
- package/engine/pdf-build.mjs +357 -34
- package/engine/pdf-images.mjs +64 -0
- package/engine/pdf-render.mjs +160 -36
- package/engine/scenes.mjs +16 -4
- package/engine/site-build.mjs +127 -13
- package/engine/site-index.mjs +72 -1
- package/engine/site-preview.mjs +2 -0
- package/engine/system-block.mjs +44 -16
- package/hm3/actors.mjs +2 -2
- package/manifest.mjs +30 -24
- package/package.json +1 -1
- package/packagebuild-metadata.jsonl +13 -13
- package/sohl/item-fields.mjs +4 -3
- package/types/content-config.d.mts +48 -1
- package/types/engine/anchors.d.mts +9 -4
- package/types/engine/art-fields.d.mts +64 -0
- package/types/engine/asset-index.d.mts +43 -0
- package/types/engine/asset-replacement.d.mts +22 -0
- package/types/engine/asset-types.d.mts +18 -0
- package/types/engine/base-compiler.d.mts +0 -17
- package/types/engine/content-embeds.d.mts +16 -0
- package/types/engine/content-figures.d.mts +101 -0
- package/types/engine/content-footnotes.d.mts +7 -0
- package/types/engine/content-images.d.mts +78 -12
- package/types/engine/content-index.d.mts +8 -2
- package/types/engine/field-reference.d.mts +21 -0
- package/types/engine/field-spec.d.mts +20 -16
- package/types/engine/foreign-catalog.d.mts +39 -0
- package/types/engine/heading-attributes.d.mts +13 -8
- package/types/engine/helpers.d.mts +23 -7
- package/types/engine/infobox-registry.d.mts +4 -1
- package/types/engine/infobox.d.mts +6 -0
- package/types/engine/journals.d.mts +31 -9
- package/types/engine/lore-events.d.mts +14 -0
- package/types/engine/markdown-expressions.d.mts +23 -2
- package/types/engine/note-dates.d.mts +64 -1
- package/types/engine/pathnames.d.mts +26 -0
- package/types/engine/pdf-build.d.mts +28 -6
- package/types/engine/pdf-images.d.mts +52 -0
- package/types/engine/pdf-render.d.mts +12 -0
- package/types/engine/site-build.d.mts +14 -3
- package/types/engine/site-index.d.mts +54 -0
- package/types/engine/system-block.d.mts +26 -2
- package/types/hm3/actors.d.mts +18 -0
- package/types/manifest.d.mts +19 -23
- package/engine/content-captions.mjs +0 -230
- package/types/engine/content-captions.d.mts +0 -58
|
@@ -51,14 +51,17 @@ export function compilesSystemDocument(fm: object, map: object, router: object):
|
|
|
51
51
|
* @param {object} [options.router] - The pack router deciding which system
|
|
52
52
|
* compiles a document for this note. Defaults to the consuming repository's.
|
|
53
53
|
* @param {object} [options.dates] - Calendar conversion context.
|
|
54
|
+
* @param {string} [options.contentPackage] - This build's content package,
|
|
55
|
+
* the default a note box's short-form Address resolves against.
|
|
54
56
|
* @returns {object[]} The boxes, in the order every medium renders them.
|
|
55
57
|
* @throws {Error} When the built set disagrees with what the note's type maps
|
|
56
58
|
* to — see {@link module:engine/infobox.assertInfoboxSet}.
|
|
57
59
|
*/
|
|
58
|
-
export function noteInfoboxes(fm: object, { resolve, router, dates }?: {
|
|
60
|
+
export function noteInfoboxes(fm: object, { resolve, router, dates, contentPackage }?: {
|
|
59
61
|
resolve?: ((ref: unknown, hint?: object) => object | undefined) | undefined;
|
|
60
62
|
router?: object | undefined;
|
|
61
63
|
dates?: object | undefined;
|
|
64
|
+
contentPackage?: string | undefined;
|
|
62
65
|
}): object[];
|
|
63
66
|
/**
|
|
64
67
|
* Every system's infobox declaration, in the order a page shows them.
|
|
@@ -154,12 +154,15 @@ export function linkValue(ref: unknown, resolve: (ref: unknown, hint?: object) =
|
|
|
154
154
|
* @param {object} [options] - Options.
|
|
155
155
|
* @param {(ref: unknown) => object|undefined} [options.resolve] - Resolves a
|
|
156
156
|
* reference to `{name, url?, uuid?, address?}`.
|
|
157
|
+
* @param {string} [options.contentPackage] - This build's content package,
|
|
158
|
+
* the default a relation row's short-form Address resolves against.
|
|
157
159
|
* @param {object} [options.vocabulary] - The note vocabulary to read.
|
|
158
160
|
* @param {object} [options.presentation] - The overlay to read.
|
|
159
161
|
* @returns {object} The box.
|
|
160
162
|
*/
|
|
161
163
|
export function noteInfobox(fm: object, options?: {
|
|
162
164
|
resolve?: ((ref: unknown) => object | undefined) | undefined;
|
|
165
|
+
contentPackage?: string | undefined;
|
|
163
166
|
vocabulary?: object | undefined;
|
|
164
167
|
presentation?: object | undefined;
|
|
165
168
|
}): object;
|
|
@@ -268,6 +271,8 @@ export function systemRowsSection(fm: object, fields: readonly object[], { block
|
|
|
268
271
|
* Resolves one declared field against the note.
|
|
269
272
|
* @param {(ref: unknown) => object|undefined} [options.resolve] - Resolves a
|
|
270
273
|
* reference to `{name, url?, uuid?, address?}`.
|
|
274
|
+
* @param {string} [options.contentPackage] - This build's content package,
|
|
275
|
+
* the default a note box's short-form Address resolves against.
|
|
271
276
|
* @param {object} [options.vocabulary] - The note vocabulary to read.
|
|
272
277
|
* @returns {object[]} The boxes.
|
|
273
278
|
*/
|
|
@@ -277,6 +282,7 @@ export function buildInfoboxes(fm: object, options: {
|
|
|
277
282
|
compilesDocument: (fm: object, map: object) => boolean;
|
|
278
283
|
resolveField: (field: object, fm: object, opts: object) => object;
|
|
279
284
|
resolve?: ((ref: unknown) => object | undefined) | undefined;
|
|
285
|
+
contentPackage?: string | undefined;
|
|
280
286
|
vocabulary?: object | undefined;
|
|
281
287
|
}): object[];
|
|
282
288
|
/**
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Splits a markdown body into pages by top-level H1 headings. Fenced
|
|
3
|
-
* code blocks are respected so `# foo` inside ``` blocks doesn't
|
|
4
|
-
* a split. Content before the first H1 (if non-empty) becomes a
|
|
5
|
-
* page. Each H1 yields a page whose name is the heading
|
|
3
|
+
* code blocks are respected so `# foo` inside ``` or ~~~ blocks doesn't
|
|
4
|
+
* trigger a split. Content before the first H1 (if non-empty) becomes a
|
|
5
|
+
* leading page. Each H1 yields a page whose name is the heading
|
|
6
6
|
* text (with any `{#anchor-id}` suffix stripped out and surfaced as
|
|
7
7
|
* `anchorSlug`). The classes the heading declares come along as `classes`, so
|
|
8
8
|
* a surface that honours one has it without reading the suffix again.
|
|
@@ -13,16 +13,26 @@
|
|
|
13
13
|
* calling that page "Introduction" would label the description as a preamble to
|
|
14
14
|
* nothing.
|
|
15
15
|
*
|
|
16
|
+
* A figure fence carries its own record along onto the page it starts, as
|
|
17
|
+
* `figure` — `null` for a page a heading started. {@link buildPages} reads it
|
|
18
|
+
* to build the `image` or `text` page a fence begins; nothing else sets it.
|
|
19
|
+
*
|
|
16
20
|
* @param {string} body - Markdown body to split.
|
|
17
21
|
* @param {string} [leadName] - Name of the page before the first heading.
|
|
22
|
+
* @param {(address: string) => string|undefined} [resolveRole] - From a
|
|
23
|
+
* picture's address to the role its asset declares, so a figure page's
|
|
24
|
+
* name reads `Map 1` rather than `Figure 1` where it is due — see
|
|
25
|
+
* {@link module:engine/content-figures.scanFigures}.
|
|
18
26
|
* @returns {Array<{name: string, anchorSlug: string|null, level: number,
|
|
19
|
-
* classes: string[], markdown: string}>} Pages in
|
|
27
|
+
* classes: string[], figure: object|null, markdown: string}>} Pages in
|
|
28
|
+
* document order.
|
|
20
29
|
*/
|
|
21
|
-
export function splitPages(body: string, leadName?: string): Array<{
|
|
30
|
+
export function splitPages(body: string, leadName?: string, resolveRole?: (address: string) => string | undefined): Array<{
|
|
22
31
|
name: string;
|
|
23
32
|
anchorSlug: string | null;
|
|
24
33
|
level: number;
|
|
25
34
|
classes: string[];
|
|
35
|
+
figure: object | null;
|
|
26
36
|
markdown: string;
|
|
27
37
|
}>;
|
|
28
38
|
/**
|
|
@@ -101,15 +111,22 @@ export function journalPageId(entryId: string, page: {
|
|
|
101
111
|
* @param {string} noteName - The note, for error messages.
|
|
102
112
|
* A page whose heading carries `.secret` is given to the GM alone, by the one
|
|
103
113
|
* ownership value Foundry reads as "nobody but a GM". Every other page states
|
|
104
|
-
* no ownership and inherits the journal's.
|
|
105
|
-
*
|
|
114
|
+
* no ownership and inherits the journal's. A figure-started page states none
|
|
115
|
+
* either: {@link scanFigures} validates a figure's classes against its own
|
|
116
|
+
* closed vocabulary, which carries no `.secret`.
|
|
117
|
+
*
|
|
118
|
+
* @param {Array<object>} figures - From {@link scanFigures}, numbered across
|
|
119
|
+
* the whole note. Read by a page a heading started; a page a figure started
|
|
120
|
+
* carries its own figure already, from {@link splitPages}.
|
|
121
|
+
* @param {(address: string) => string|undefined} [resolveRole] - See
|
|
122
|
+
* {@link splitPages}.
|
|
106
123
|
* @returns {Array<{_id: string, name: string, type: string,
|
|
107
124
|
* title: {show: boolean, level: number},
|
|
108
125
|
* text: {format: number, content: string}, _key: string,
|
|
109
126
|
* ownership?: {default: number}}>} The page documents, in order.
|
|
110
127
|
* @throws {Error} When the note has no content at all, or repeats an anchor.
|
|
111
128
|
*/
|
|
112
|
-
export function buildPages(rawPages: Array<object>, entryId: string, noteName: string,
|
|
129
|
+
export function buildPages(rawPages: Array<object>, entryId: string, noteName: string, figures: Array<object>, resolveRole?: (address: string) => string | undefined): Array<{
|
|
113
130
|
_id: string;
|
|
114
131
|
name: string;
|
|
115
132
|
type: string;
|
|
@@ -156,9 +173,13 @@ export function buildPages(rawPages: Array<object>, entryId: string, noteName: s
|
|
|
156
173
|
* module:engine/draft-notice}. It leads the first authored page,
|
|
157
174
|
* because a reader deciding whether to rely on the entry has to be told
|
|
158
175
|
* before they read it rather than after.
|
|
176
|
+
* @param {(address: string) => string|undefined} [params.resolveRole] - From
|
|
177
|
+
* a picture's address to the role its asset declares, so a figure page's
|
|
178
|
+
* name reads `Map 1` rather than `Figure 1` where it is due — see
|
|
179
|
+
* {@link module:engine/content-figures.scanFigures}.
|
|
159
180
|
* @returns {object} The JournalEntry document, keyed for the pack.
|
|
160
181
|
*/
|
|
161
|
-
export function buildJournalEntry({ id, name, markdown, leadName, folder, stats, infoboxes, notice, }: {
|
|
182
|
+
export function buildJournalEntry({ id, name, markdown, leadName, folder, stats, infoboxes, notice, resolveRole, }: {
|
|
162
183
|
id: string;
|
|
163
184
|
name: string;
|
|
164
185
|
markdown: string;
|
|
@@ -171,6 +192,7 @@ export function buildJournalEntry({ id, name, markdown, leadName, folder, stats,
|
|
|
171
192
|
html: string;
|
|
172
193
|
}[] | undefined;
|
|
173
194
|
notice?: string | undefined;
|
|
195
|
+
resolveRole?: ((address: string) => string | undefined) | undefined;
|
|
174
196
|
}): object;
|
|
175
197
|
/**
|
|
176
198
|
* Journals pack compiler.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validate one `lore` note's `data.events`.
|
|
3
|
+
*
|
|
4
|
+
* Registered as the `events` field's own `check` in `note-vocabulary.mjs`, so
|
|
5
|
+
* it runs on every `lore` note regardless of `subType` — an occasion is not a
|
|
6
|
+
* calendar fact, and nothing here is scoped to `subType: calendar`.
|
|
7
|
+
*
|
|
8
|
+
* @param {object} note - The note, as the link index hands it over.
|
|
9
|
+
* @param {{index?: object}} [options]
|
|
10
|
+
* @returns {object[]} Findings, each positioned at the entry that earned it.
|
|
11
|
+
*/
|
|
12
|
+
export function checkLoreEvents(note: object, { index }?: {
|
|
13
|
+
index?: object;
|
|
14
|
+
}): object[];
|
|
@@ -3,12 +3,33 @@ export function sqlQueriesInMarkdown(body: any, fm?: {}): any[];
|
|
|
3
3
|
/**
|
|
4
4
|
* Expand scalar frontmatter references and registered functions in Markdown prose.
|
|
5
5
|
* @param {string} body
|
|
6
|
-
* @param {{fm?: object, dates?: object, sqlResults?: Map<string, object>,
|
|
6
|
+
* @param {{fm?: object, dates?: object, sqlResults?: Map<string, object>,
|
|
7
|
+
* figures?: {get: (id: string) => {label: string, caption: string,
|
|
8
|
+
* hasCaption: boolean}|undefined, note?: (address: string) =>
|
|
9
|
+
* {url: string|null, figures: Map<string, object>}|undefined,
|
|
10
|
+
* link?: Function}, file?: string, bodyLine?: number}} [options] -
|
|
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
|
|
13
|
+
* way a wikilink would — omitted, a cross-note address is refused rather
|
|
14
|
+
* than looked up. `link` overrides how a resolved reference renders; the
|
|
15
|
+
* default is a Markdown link to the target's own anchor.
|
|
7
16
|
*/
|
|
8
|
-
export function renderMarkdownExpressions(body: string, { fm, dates, sqlResults, file, bodyLine }?: {
|
|
17
|
+
export function renderMarkdownExpressions(body: string, { fm, dates, sqlResults, figures, file, bodyLine }?: {
|
|
9
18
|
fm?: object;
|
|
10
19
|
dates?: object;
|
|
11
20
|
sqlResults?: Map<string, object>;
|
|
21
|
+
figures?: {
|
|
22
|
+
get: (id: string) => {
|
|
23
|
+
label: string;
|
|
24
|
+
caption: string;
|
|
25
|
+
hasCaption: boolean;
|
|
26
|
+
} | undefined;
|
|
27
|
+
note?: (address: string) => {
|
|
28
|
+
url: string | null;
|
|
29
|
+
figures: Map<string, object>;
|
|
30
|
+
} | undefined;
|
|
31
|
+
link?: Function;
|
|
32
|
+
};
|
|
12
33
|
file?: string;
|
|
13
34
|
bodyLine?: number;
|
|
14
35
|
}): {
|
|
@@ -91,8 +91,71 @@ export function formatNoteDate(date: any, era: any, daysPerYear: any, formatName
|
|
|
91
91
|
text: string;
|
|
92
92
|
prose: string | null;
|
|
93
93
|
} | null;
|
|
94
|
+
/**
|
|
95
|
+
* The occurrences of one recurring series overlapping a bound.
|
|
96
|
+
*
|
|
97
|
+
* **No materialized occurrence list.** An annual series anchored centuries
|
|
98
|
+
* back has thousands of occurrences to the present, and the only questions a
|
|
99
|
+
* build asks are "is this year one of them" and "which is next" — so an
|
|
100
|
+
* omitted bound answers with a single occurrence rather than every one a live
|
|
101
|
+
* series could have:
|
|
102
|
+
*
|
|
103
|
+
* - `to` omitted: the first occurrence at or after `from` (default, the
|
|
104
|
+
* anchor's own year) — "next".
|
|
105
|
+
* - `from` omitted, `to` given: the last occurrence at or before `to` —
|
|
106
|
+
* "the greatest occurrence at or before `until`".
|
|
107
|
+
* - Both given: every occurrence between them, inclusive — a membership
|
|
108
|
+
* probe is `from === to`.
|
|
109
|
+
*
|
|
110
|
+
* **The lower bound is not optional.** A candidate year before the anchor's
|
|
111
|
+
* own year is never an occurrence, however a bare modulo would read it: `%`
|
|
112
|
+
* takes the sign of its dividend in both JavaScript and SQL, so a year
|
|
113
|
+
* exactly one period before the anchor would otherwise match. `k` is clamped
|
|
114
|
+
* at zero rather than left to run negative.
|
|
115
|
+
*
|
|
116
|
+
* **The period advances the canonical year, never the era-relative year.**
|
|
117
|
+
* `date.canonicalYear` is already on the continuous axis `canonicalYear`
|
|
118
|
+
* builds — era year `-1` sits immediately before era year `1`, but canonical
|
|
119
|
+
* year `0` is an ordinary integer between them — so stepping by whole
|
|
120
|
+
* multiples of `every` on `canonicalYear` crosses an epoch with no special
|
|
121
|
+
* case. Counting in era-relative years instead would need a correction at
|
|
122
|
+
* every crossing and silently loses one year each time it is forgotten.
|
|
123
|
+
*
|
|
124
|
+
* **Precision, approximation and the day of year carry through untouched.**
|
|
125
|
+
* Every occurrence is the anchor's own record with only `canonicalYear`
|
|
126
|
+
* advanced, so a day-precision anchor's `canonicalDay` — including one inside
|
|
127
|
+
* a short intercalary month — names the same day of every occurrence, and an
|
|
128
|
+
* approximate anchor's occurrences are approximate too.
|
|
129
|
+
*
|
|
130
|
+
* @param {object} date - The anchor's resolved record
|
|
131
|
+
* ({@link parseNoteDate}), carrying a real `canonicalYear`. A year-0 "any
|
|
132
|
+
* year" anchor carries none and has no series through this function — its
|
|
133
|
+
* `recurs` is refused, and its own next occurrence is computed directly
|
|
134
|
+
* from the day of year alone.
|
|
135
|
+
* @param {{every?: number, on?: object[]}} [recurs] - The declared
|
|
136
|
+
* recurrence: a whole-year period, or an enumeration of further resolved
|
|
137
|
+
* date records (each already carrying its own `canonicalYear`). Neither
|
|
138
|
+
* admits the other.
|
|
139
|
+
* @param {object} [bounds]
|
|
140
|
+
* @param {number} [bounds.from] - The lower bound, inclusive, as a canonical
|
|
141
|
+
* year.
|
|
142
|
+
* @param {number} [bounds.to] - The upper bound, inclusive, as a canonical
|
|
143
|
+
* year.
|
|
144
|
+
* @returns {object[]} Occurrence records, in increasing order.
|
|
145
|
+
*/
|
|
146
|
+
export function occurrencesOf(date: object, recurs?: {
|
|
147
|
+
every?: number;
|
|
148
|
+
on?: object[];
|
|
149
|
+
}, { from, to }?: {
|
|
150
|
+
from?: number | undefined;
|
|
151
|
+
to?: number | undefined;
|
|
152
|
+
}): object[];
|
|
94
153
|
/** Normalize a note's declared dates for indexes and generated pages. */
|
|
95
|
-
export function resolvedDateFields(fm: any, context: any): {
|
|
154
|
+
export function resolvedDateFields(fm: any, context: any): {
|
|
155
|
+
events: any;
|
|
156
|
+
} | {
|
|
157
|
+
events?: undefined;
|
|
158
|
+
};
|
|
96
159
|
/**
|
|
97
160
|
* The literal that says a thing happened and the date is not recorded.
|
|
98
161
|
*
|
|
@@ -82,6 +82,32 @@ export function packageAddresses(config: object): Map<string, {
|
|
|
82
82
|
* resolves on one surface and nowhere else.
|
|
83
83
|
*/
|
|
84
84
|
export function resolvePathname(raw: string | null | undefined, config: object): PathnameForms | null;
|
|
85
|
+
/**
|
|
86
|
+
* The pathname one authored image address keys an asset's role and pixel
|
|
87
|
+
* size under — `<package>/assets/<suffix>`, the same key
|
|
88
|
+
* {@link module:engine/art-fields.assetImageInfoByPathname} builds from the
|
|
89
|
+
* asset record itself.
|
|
90
|
+
*
|
|
91
|
+
* **Why this exists apart from `resolvePathname`'s own forms.** An embed
|
|
92
|
+
* rewrites to that exact pathname — see
|
|
93
|
+
* {@link module:engine/content-embeds.resolveEmbeds} — but an author's own
|
|
94
|
+
* body image is free to write the bare, own-package form instead
|
|
95
|
+
* (`images/m.webp`), which names the identical file without naming the
|
|
96
|
+
* package. The two forms have to key the same lookup, and `resolvePathname`
|
|
97
|
+
* already answers which package a bare form belongs to; this just restates
|
|
98
|
+
* that answer in the one shape a renderer looks a picture's role up by.
|
|
99
|
+
*
|
|
100
|
+
* **Never throws.** A lookup is a best-effort read, not a validation — the
|
|
101
|
+
* pathname lint is what refuses a Foundry-spelled address — so a value
|
|
102
|
+
* {@link resolvePathname} refuses outright answers `null` here as well, the
|
|
103
|
+
* same as a blank or an external one.
|
|
104
|
+
*
|
|
105
|
+
* @param {string} src - The address, as authored or as an embed resolved it.
|
|
106
|
+
* @param {object} config - The resolved build configuration.
|
|
107
|
+
* @returns {string|null} The pathname, or `null` for an address naming no
|
|
108
|
+
* asset record to look up.
|
|
109
|
+
*/
|
|
110
|
+
export function assetPathnameKey(src: string, config: object): string | null;
|
|
85
111
|
/**
|
|
86
112
|
* The directory a package ships its files in, and the segment that marks a
|
|
87
113
|
* pathname's first segment as a package name.
|
|
@@ -13,17 +13,34 @@
|
|
|
13
13
|
* makes the source a consumer can compile by hand with no flags, and what keeps
|
|
14
14
|
* a build from touching a path outside its own output.
|
|
15
15
|
*
|
|
16
|
-
*
|
|
17
|
-
* package's file
|
|
18
|
-
*
|
|
19
|
-
*
|
|
16
|
+
* A file **this** package ships stages directly. A pathname naming another
|
|
17
|
+
* package's file stages instead from a declared replacement's cached archive,
|
|
18
|
+
* when `opts.resolveReplacement` — the pure function
|
|
19
|
+
* {@link module:engine/asset-replacement.resolveAssetReplacement} —
|
|
20
|
+
* answers it; `opts.foreignIndex` is the merged index that answer is read
|
|
21
|
+
* against. A pathname naming a package no replacement carries it for, or a
|
|
22
|
+
* URL, names something no build here can open — a build reaches no network —
|
|
23
|
+
* and the caller reports it as a picture the book will not carry.
|
|
20
24
|
*
|
|
21
25
|
* @param {string} src - The pathname, as authored.
|
|
22
26
|
* @param {object} config - The resolved configuration.
|
|
27
|
+
* @param {object} [opts]
|
|
28
|
+
* @param {Map<string, object>} [opts.foreignIndex] - Every fetched
|
|
29
|
+
* dependency's own records, keyed by canonical address — the index a
|
|
30
|
+
* replacement's record is read out of.
|
|
31
|
+
* @param {Function} [opts.resolveReplacement] - {@link
|
|
32
|
+
* module:engine/asset-replacement.resolveAssetReplacement}, or an
|
|
33
|
+
* equivalent a caller injects for a test. Omitted, a foreign pathname this
|
|
34
|
+
* package does not own stays declined exactly as it always has.
|
|
23
35
|
* @returns {{from: string, to: string}|null} The file, and where under the
|
|
24
36
|
* output directory it is staged.
|
|
37
|
+
* @throws {Error} When a declared replacement answers the address but its
|
|
38
|
+
* archive was never fetched.
|
|
25
39
|
*/
|
|
26
|
-
export function stagedImagePath(src: string, config: object
|
|
40
|
+
export function stagedImagePath(src: string, config: object, opts?: {
|
|
41
|
+
foreignIndex?: Map<string, object> | undefined;
|
|
42
|
+
resolveReplacement?: Function | undefined;
|
|
43
|
+
}): {
|
|
27
44
|
from: string;
|
|
28
45
|
to: string;
|
|
29
46
|
} | null;
|
|
@@ -66,13 +83,18 @@ export function pdfFileName(artifact: string, version: string): string;
|
|
|
66
83
|
* @param {string} [opts.version] - Stamped on the title page and the file name.
|
|
67
84
|
* @param {boolean} [opts.compile] - Whether to run Typst. False leaves the
|
|
68
85
|
* `.typ` source, which is what the unit tests read.
|
|
86
|
+
* @param {Function} [opts.resolveReplacement] - {@link
|
|
87
|
+
* module:engine/asset-replacement.resolveAssetReplacement}, for tests.
|
|
88
|
+
* Loaded from that module otherwise, and only when a relationship declares
|
|
89
|
+
* `assetReplacement: true` — a build with none never imports it.
|
|
69
90
|
* @returns {Promise<object>} `{ built, reason, findings, typ, pdf, stats }`.
|
|
70
91
|
*/
|
|
71
|
-
export function buildPdf({ config, out, version, compile }?: {
|
|
92
|
+
export function buildPdf({ config, out, version, compile, resolveReplacement, }?: {
|
|
72
93
|
config?: object | undefined;
|
|
73
94
|
out?: string | undefined;
|
|
74
95
|
version?: string | undefined;
|
|
75
96
|
compile?: boolean | undefined;
|
|
97
|
+
resolveReplacement?: Function | undefined;
|
|
76
98
|
}): Promise<object>;
|
|
77
99
|
/**
|
|
78
100
|
* The command line the compile runs, as data.
|
|
@@ -1,3 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The width the book draws one picture at, in inches, when nothing authored
|
|
3
|
+
* narrows it to a named `size=`.
|
|
4
|
+
*
|
|
5
|
+
* > drawn width = min(the role's slot, natural pixels ÷ the print floor)
|
|
6
|
+
*
|
|
7
|
+
* **Every size here is a maximum, never a target**: a picture is never drawn
|
|
8
|
+
* larger than it was made. The print floor is {@link PDF_PAGE.dpi}, the same
|
|
9
|
+
* constant the page geometry above is set against, so a role's slot and the
|
|
10
|
+
* page it is drawn on cannot disagree about what a pixel is worth.
|
|
11
|
+
*
|
|
12
|
+
* An icon-type address takes the nominal icon width whatever role it might
|
|
13
|
+
* otherwise carry — `role` never reaches one, since the asset record refuses
|
|
14
|
+
* it there. A vector carries no pixel count, so nothing narrows its role's
|
|
15
|
+
* slot. A picture declaring no role answers `undefined`: the medium's
|
|
16
|
+
* ordinary size, decided elsewhere by a named `size=` or by its own natural
|
|
17
|
+
* pixels within whatever it is set in.
|
|
18
|
+
*
|
|
19
|
+
* @param {object} [asset] - What {@link module:engine/art-fields.assetImageInfoByPathname}
|
|
20
|
+
* records for the picture's address.
|
|
21
|
+
* @param {string} [asset.type] - The asset's type — `icon` or `image`.
|
|
22
|
+
* @param {string} [asset.role] - The picture's declared role.
|
|
23
|
+
* @param {number|""} [asset.width] - The file's own pixel width; blank for a vector.
|
|
24
|
+
* @returns {number|undefined} The drawn width, in inches.
|
|
25
|
+
*/
|
|
26
|
+
export function bookImageWidthIn({ type, role, width }?: {
|
|
27
|
+
type?: string | undefined;
|
|
28
|
+
role?: string | undefined;
|
|
29
|
+
width?: number | "" | undefined;
|
|
30
|
+
}): number | undefined;
|
|
1
31
|
/**
|
|
2
32
|
* Optimize staged raster images without changing their authored files.
|
|
3
33
|
*
|
|
@@ -36,3 +66,25 @@ export const pdfTextWidth: number;
|
|
|
36
66
|
/** Usable height of a portrait page in inches. */
|
|
37
67
|
export const pdfTextHeight: number;
|
|
38
68
|
export function pdfColumnWidth(columns?: number): number;
|
|
69
|
+
/**
|
|
70
|
+
* The fraction of the page's one-column measure a picture's role may fill at
|
|
71
|
+
* most — one table, read by {@link bookImageWidthIn}, so a policy change here
|
|
72
|
+
* is the one line it costs rather than an edit to every note drawing a role.
|
|
73
|
+
*
|
|
74
|
+
* A `portrait` or an `emblem` names a subject or a mark, which sits beside
|
|
75
|
+
* prose rather than replacing a page of it; a `banner`, a `plate` and a `map`
|
|
76
|
+
* are each meant to be looked at in full. The measure is the page's own text
|
|
77
|
+
* width, {@link pdfTextWidth}, so a role's slot does not shrink when a page
|
|
78
|
+
* happens to be set in two columns — it is what the picture is *for* that
|
|
79
|
+
* sets the slot, not the layout it lands in.
|
|
80
|
+
*
|
|
81
|
+
* @type {Readonly<Record<string, number>>}
|
|
82
|
+
*/
|
|
83
|
+
export const BOOK_ROLE_SLOTS: Readonly<Record<string, number>>;
|
|
84
|
+
/**
|
|
85
|
+
* The book's nominal width for an icon-type picture, in inches, whatever its
|
|
86
|
+
* file holds — almost every icon is an SVG with no pixel count to measure.
|
|
87
|
+
*
|
|
88
|
+
* @type {number}
|
|
89
|
+
*/
|
|
90
|
+
export const BOOK_ICON_WIDTH_IN: number;
|
|
@@ -69,6 +69,12 @@ export function stripHtmlComments(markdown: string): string;
|
|
|
69
69
|
* the staged file's path, relative to the `.typ`. An address this does not
|
|
70
70
|
* carry has no file the compiler can open, so the figure prints its caption
|
|
71
71
|
* alone — see {@link renderImage}.
|
|
72
|
+
* @param {Map<string, {type: string, role?: string, width: number|"", height: number|""}>}
|
|
73
|
+
* [opts.assets] - An image's address as authored → what
|
|
74
|
+
* {@link module:engine/art-fields.assetImageInfoByPathname} records for it,
|
|
75
|
+
* which is what sizes a picture carrying no named `size=` — see
|
|
76
|
+
* {@link module:engine/pdf-images.bookImageWidthIn}. An address missing from
|
|
77
|
+
* this map draws at the medium's ordinary size, the same as today.
|
|
72
78
|
* @param {number} [opts.headingOffset] - Added to every heading level, so a
|
|
73
79
|
* note's own `##` nests beneath the entry heading the book gave it.
|
|
74
80
|
* @param {string} [opts.anchorPrefix] - The entry's anchor, which namespaces
|
|
@@ -101,6 +107,12 @@ export function markdownToTypst(markdown: string, opts?: {
|
|
|
101
107
|
links?: Map<string, string> | undefined;
|
|
102
108
|
glyphs?: Map<string, string> | undefined;
|
|
103
109
|
images?: Map<string, string> | undefined;
|
|
110
|
+
assets?: Map<string, {
|
|
111
|
+
type: string;
|
|
112
|
+
role?: string;
|
|
113
|
+
width: number | "";
|
|
114
|
+
height: number | "";
|
|
115
|
+
}> | undefined;
|
|
104
116
|
headingOffset?: number | undefined;
|
|
105
117
|
anchorPrefix?: string | undefined;
|
|
106
118
|
findings?: object[] | undefined;
|
|
@@ -237,7 +237,7 @@ export function pageDestination(page: {
|
|
|
237
237
|
bundle?: boolean | undefined;
|
|
238
238
|
}): string;
|
|
239
239
|
/** Transform one content page without writing the site mount. */
|
|
240
|
-
export function renderSitePage(page: any, { index, foreign, universe, pass, decorate, linkable, sqlTables, config, artIndex, }: {
|
|
240
|
+
export function renderSitePage(page: any, { index, foreign, universe, pass, decorate, linkable, sqlTables, config, artIndex, figuresByAddress, }: {
|
|
241
241
|
index: any;
|
|
242
242
|
foreign: any;
|
|
243
243
|
universe: any;
|
|
@@ -247,6 +247,7 @@ export function renderSitePage(page: any, { index, foreign, universe, pass, deco
|
|
|
247
247
|
sqlTables: any;
|
|
248
248
|
config: any;
|
|
249
249
|
artIndex: any;
|
|
250
|
+
figuresByAddress?: Map<any, any> | undefined;
|
|
250
251
|
}): {
|
|
251
252
|
page: any;
|
|
252
253
|
body: string;
|
|
@@ -280,6 +281,13 @@ export function renderSitePage(page: any, { index, foreign, universe, pass, deco
|
|
|
280
281
|
}[];
|
|
281
282
|
wikiErrors: any[];
|
|
282
283
|
imageErrors: any[];
|
|
284
|
+
embedErrors: {
|
|
285
|
+
file: string;
|
|
286
|
+
line: number;
|
|
287
|
+
column: number | undefined;
|
|
288
|
+
severity: "error";
|
|
289
|
+
message: string;
|
|
290
|
+
}[];
|
|
283
291
|
};
|
|
284
292
|
/**
|
|
285
293
|
* Renders and writes every page.
|
|
@@ -316,7 +324,7 @@ export function renderSitePage(page: any, { index, foreign, universe, pass, deco
|
|
|
316
324
|
* it by wikilink, and its own markdown links name content pages. `maps` is
|
|
317
325
|
* each drawing by the URL of the page that carries it.
|
|
318
326
|
* @returns {{written: number, byKind: Record<string, number>, tableErrors: object[],
|
|
319
|
-
* wikiErrors: object[], imageErrors: object[],
|
|
327
|
+
* wikiErrors: object[], imageErrors: object[], embedErrors: object[],
|
|
320
328
|
* related: Map<string, import("./related-pages.mjs").Related>,
|
|
321
329
|
* maps: number}} `related`
|
|
322
330
|
* is keyed by page URL, and holds the homepage's block beside every content
|
|
@@ -329,6 +337,7 @@ export function renderPages(pages: object[], options: object): {
|
|
|
329
337
|
tableErrors: object[];
|
|
330
338
|
wikiErrors: object[];
|
|
331
339
|
imageErrors: object[];
|
|
340
|
+
embedErrors: object[];
|
|
332
341
|
related: Map<string, import("./related-pages.mjs").Related>;
|
|
333
342
|
maps: number;
|
|
334
343
|
};
|
|
@@ -361,7 +370,8 @@ export function sitePageDecorator(config: any, index: any): (data: any, page: an
|
|
|
361
370
|
* `sql` directive with none prepared is a table error: nothing here runs a
|
|
362
371
|
* query.
|
|
363
372
|
* @returns {{gates: object, stats: object|null, tableErrors: object[],
|
|
364
|
-
* wikiErrors: object[], imageErrors: object[],
|
|
373
|
+
* wikiErrors: object[], imageErrors: object[], embedErrors: object[],
|
|
374
|
+
* mapFindings: object[],
|
|
365
375
|
* manifests: object|null}} `mapFindings` is what drawing the maps found —
|
|
366
376
|
* warnings, never a reason to fail the build.
|
|
367
377
|
*/
|
|
@@ -374,6 +384,7 @@ export function buildSite({ config, sqlTables }?: {
|
|
|
374
384
|
tableErrors: object[];
|
|
375
385
|
wikiErrors: object[];
|
|
376
386
|
imageErrors: object[];
|
|
387
|
+
embedErrors: object[];
|
|
377
388
|
mapFindings: object[];
|
|
378
389
|
manifests: object | null;
|
|
379
390
|
};
|
|
@@ -24,6 +24,60 @@ export function buildSiteIndex(entries: readonly SiteEntry[], { foreignIndex, no
|
|
|
24
24
|
records?: object[] | undefined;
|
|
25
25
|
foreignReferences?: Map<string, object> | undefined;
|
|
26
26
|
}): SiteIndex;
|
|
27
|
+
/**
|
|
28
|
+
* The address keys one page's figures are reachable by — the same two forms
|
|
29
|
+
* {@link buildSiteIndex} assigns the page itself, so a `ref` crossing into it
|
|
30
|
+
* resolves by exactly the address a wikilink would use.
|
|
31
|
+
*
|
|
32
|
+
* @param {string} pkg - The page's own content package.
|
|
33
|
+
* @param {string} type - The note's `type`.
|
|
34
|
+
* @param {string} shortcode - The note's `shortcode`.
|
|
35
|
+
* @returns {Set<string>} The short `type/shortcode` key and the canonical
|
|
36
|
+
* `package-system-type-shortcode` one.
|
|
37
|
+
*/
|
|
38
|
+
export function figureIndexKeys(pkg: string, type: string, shortcode: string): Set<string>;
|
|
39
|
+
/**
|
|
40
|
+
* Resolve a `ref` call's cross-note address to the target's own figures and
|
|
41
|
+
* its own address — the `figures.note` a `ref` helper's render context reads,
|
|
42
|
+
* built once and threaded into every page.
|
|
43
|
+
*
|
|
44
|
+
* Reads the written address exactly as a wikilink does
|
|
45
|
+
* ({@link readQualifier}, {@link expandAddress}), so a `ref` crossing into
|
|
46
|
+
* another note and a `[[…]]` link to the same note agree on what resolves and
|
|
47
|
+
* what does not: a target naming no known type or no fetched package's index
|
|
48
|
+
* is unresolved for both, and one address names one note for both.
|
|
49
|
+
*
|
|
50
|
+
* @param {string} target - The address as written, anchor already removed —
|
|
51
|
+
* {@link module:engine/wikilink-syntax.ParsedWikilink.target}.
|
|
52
|
+
* @param {object} options
|
|
53
|
+
* @param {Set<string>} options.contentTypes - Every type this build reads as
|
|
54
|
+
* an address qualifier.
|
|
55
|
+
* @param {Set<string>} options.packages - Every package an address may name.
|
|
56
|
+
* @param {Set<string>} options.noIndexPackages - Packages declared
|
|
57
|
+
* `contentIndex: false`.
|
|
58
|
+
* @param {string} options.contentPackage - The package a target with no
|
|
59
|
+
* package segment defaults to.
|
|
60
|
+
* @param {Map<string, {url: string}>} options.siteIndexMap - {@link SiteIndex}'s
|
|
61
|
+
* own `index`, read for the target's existence and its URL.
|
|
62
|
+
* @param {Map<string, Map<string, object>>} options.figuresByAddress - Every
|
|
63
|
+
* note's figures, by id, keyed as {@link figureIndexKeys} keys the note.
|
|
64
|
+
* @returns {{url: string, figures: Map<string, object>}|undefined} The
|
|
65
|
+
* target's own address and figures, or `undefined` when the address names
|
|
66
|
+
* no note this build resolves.
|
|
67
|
+
*/
|
|
68
|
+
export function resolveCrossNoteFigures(target: string, { contentTypes, packages, noIndexPackages, contentPackage, siteIndexMap, figuresByAddress }: {
|
|
69
|
+
contentTypes: Set<string>;
|
|
70
|
+
packages: Set<string>;
|
|
71
|
+
noIndexPackages: Set<string>;
|
|
72
|
+
contentPackage: string;
|
|
73
|
+
siteIndexMap: Map<string, {
|
|
74
|
+
url: string;
|
|
75
|
+
}>;
|
|
76
|
+
figuresByAddress: Map<string, Map<string, object>>;
|
|
77
|
+
}): {
|
|
78
|
+
url: string;
|
|
79
|
+
figures: Map<string, object>;
|
|
80
|
+
} | undefined;
|
|
27
81
|
/**
|
|
28
82
|
* The per-page context a wikilink resolver takes.
|
|
29
83
|
*
|
|
@@ -95,8 +95,32 @@ export function sharedProperty(fm: object, source: string, defaultValue?: any):
|
|
|
95
95
|
*/
|
|
96
96
|
export function blockProperty(fm: object, block: string, key: string, defaultValue?: any): any;
|
|
97
97
|
/**
|
|
98
|
-
* A system override followed by a shared `data:` value
|
|
99
|
-
*
|
|
98
|
+
* A system override followed by a shared `data:` value followed by the
|
|
99
|
+
* retiring top-level spelling `data:` gathered it off, reporting which one
|
|
100
|
+
* answered.
|
|
101
|
+
*
|
|
102
|
+
* {@link module:engine/field-spec.resolveFieldValue}'s counterpart for a
|
|
103
|
+
* universal `data:` key — `pack` and `packFolder`, declared for every note
|
|
104
|
+
* type rather than per type, so neither is a `FieldSpec` that resolver takes.
|
|
105
|
+
* The order is the same shape: a system's own override, then the shared
|
|
106
|
+
* `data:` position, then the bare top-level key a tree authored before
|
|
107
|
+
* `data:` existed. The top-level value stays readable while a tree still on
|
|
108
|
+
* it moves its authored fields.
|
|
109
|
+
*
|
|
110
|
+
* @param {object} fm - The note's frontmatter.
|
|
111
|
+
* @param {string} block - The system block key.
|
|
112
|
+
* @param {string} key - The shared property.
|
|
113
|
+
* @param {any} [defaultValue] - Returned when no position declares it.
|
|
114
|
+
* @returns {{value: any, from: FieldSource}} The value, and where it came
|
|
115
|
+
* from.
|
|
116
|
+
*/
|
|
117
|
+
export function resolveDataProperty(fm: object, block: string, key: string, defaultValue?: any): {
|
|
118
|
+
value: any;
|
|
119
|
+
from: FieldSource;
|
|
120
|
+
};
|
|
121
|
+
/**
|
|
122
|
+
* {@link resolveDataProperty}'s value alone, for a caller that only compiles
|
|
123
|
+
* a document and has no use for which position answered.
|
|
100
124
|
*
|
|
101
125
|
* @param {object} fm - The note's frontmatter.
|
|
102
126
|
* @param {string} block - The system block key.
|
package/types/hm3/actors.d.mts
CHANGED
|
@@ -1,3 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Native HM3 facts shared by its actor subtypes.
|
|
3
|
+
*
|
|
4
|
+
* Species is native text. The note's lore Address in `data.species` is
|
|
5
|
+
* independent and supplies no native value.
|
|
6
|
+
*
|
|
7
|
+
* @type {readonly import("../engine/field-spec.mjs").FieldSpec[]}
|
|
8
|
+
*/
|
|
9
|
+
export const ACTOR_FIELDS: readonly import("../engine/field-spec.mjs").FieldSpec[];
|
|
10
|
+
/**
|
|
11
|
+
* The two `data:` facts HM3 declares on a `character` and not on a `creature`.
|
|
12
|
+
*
|
|
13
|
+
* Both name their shared source and their legacy in-block key, for the reason
|
|
14
|
+
* {@link ACTOR_FIELDS} does.
|
|
15
|
+
*
|
|
16
|
+
* @type {readonly import("../engine/field-spec.mjs").FieldSpec[]}
|
|
17
|
+
*/
|
|
18
|
+
export const CHARACTER_FIELDS: readonly import("../engine/field-spec.mjs").FieldSpec[];
|
|
1
19
|
/**
|
|
2
20
|
* HM3's Actor compile pass.
|
|
3
21
|
*
|